search_flights
Search for flights by specifying origin, destination, dates, cabin class, and passenger details to find available options for one-way, round-trip, or multi-city travel.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Type of flight | |
| origin | Yes | Origin airport or city IATA code (e.g., SFO, NYC) | |
| destination | Yes | Destination airport or city IATA code (e.g., LAX, LHR) | |
| departureDate | Yes | Departure date in YYYY-MM-DD format | |
| returnDate | No | Return date in YYYY-MM-DD format (required for round-trip) | |
| departureTime | No | Preferred departure time window | |
| arrivalTime | No | Preferred arrival time window | |
| cabinClass | Yes | Cabin class | |
| adults | No | Number of adult passengers | |
| maxConnections | No | Maximum number of connections | |
| additionalStops | No | Additional stops for multi-city flights |
Implementation Reference
- src/server.ts:30-113 (handler)Primary handler and registration for the 'search_flights' tool. Constructs flight slices based on one-way, round-trip, or multi-city parameters and queries the Duffel API for offers.server.tool( 'search_flights', flightSearchSchema.shape, async (params: FlightSearch) => { try { const slices = []; // Build slices based on flight type if (params.type === 'one_way') { slices.push(flightClient.createSlice( params.origin, params.destination, params.departureDate, params.departureTime, params.arrivalTime )); } else if (params.type === 'round_trip') { if (!params.returnDate) { throw new Error('Return date required for round-trip flights'); } slices.push(flightClient.createSlice( params.origin, params.destination, params.departureDate, params.departureTime, params.arrivalTime )); slices.push(flightClient.createSlice( params.destination, params.origin, params.returnDate, params.departureTime, params.arrivalTime )); } else if (params.type === 'multi_city') { if (!params.additionalStops || params.additionalStops.length === 0) { throw new Error('Additional stops required for multi-city flights'); } // First leg slices.push(flightClient.createSlice( params.origin, params.destination, params.departureDate )); // Additional legs for (const stop of params.additionalStops) { slices.push(flightClient.createSlice( stop.origin, stop.destination, stop.departureDate )); } } // Create the offer request const response = await flightClient.createOfferRequest({ slices, cabin_class: params.cabinClass, adult_count: params.adults, max_connections: params.maxConnections, return_offers: true, supplier_timeout: 15000 // 15 seconds }); // Return formatted response return { content: [ { type: 'text', text: JSON.stringify(response, null, 2) } ] }; } catch (error) { console.error(`Error searching flights: ${error}`); throw error; } } );
- src/models/flightSearch.ts:21-33 (schema)Zod schema defining the input parameters for the search_flights tool, including flight type, airports, dates, and preferences.export const flightSearchSchema = z.object({ type: z.enum(['one_way', 'round_trip', 'multi_city']).describe('Type of flight'), origin: z.string().describe('Origin airport or city IATA code (e.g., SFO, NYC)'), destination: z.string().describe('Destination airport or city IATA code (e.g., LAX, LHR)'), departureDate: z.string().describe('Departure date in YYYY-MM-DD format'), returnDate: z.string().optional().describe('Return date in YYYY-MM-DD format (required for round-trip)'), departureTime: timeSpecSchema.optional().describe('Preferred departure time window'), arrivalTime: timeSpecSchema.optional().describe('Preferred arrival time window'), cabinClass: z.enum(['economy', 'premium_economy', 'business', 'first']).describe('Cabin class'), adults: z.number().min(1).default(1).describe('Number of adult passengers'), maxConnections: z.number().optional().describe('Maximum number of connections'), additionalStops: z.array(flightSegmentSchema).optional().describe('Additional stops for multi-city flights') });
- src/api/duffelClient.ts:228-264 (helper)Helper function createSlice used extensively in the handler to build Duffel API slice objects for each leg of the trip.createSlice( origin: string, destination: string, date: string, departureTime?: TimeSpec, arrivalTime?: TimeSpec ): Slice { const slice: Slice = { origin, destination, departure_date: date, departure_time: { from: '00:00', to: '23:59' }, arrival_time: { from: '00:00', to: '23:59' } }; if (departureTime) { slice.departure_time = { from: departureTime.fromTime, to: departureTime.toTime }; } if (arrivalTime) { slice.arrival_time = { from: arrivalTime.fromTime, to: arrivalTime.toTime }; } return slice; }
- src/api/duffelClient.ts:93-205 (helper)Core helper method that makes the actual Duffel API call to create flight offer requests using the constructed slices.async createOfferRequest(params: OfferRequestParams): Promise<FormattedOfferResponse> { try { // Prepare the passengers array const passengers = Array(params.adult_count).fill({ type: 'adult' }); // Create the request data const requestData = { data: { slices: params.slices, passengers, cabin_class: params.cabin_class } }; if (params.max_connections !== undefined) { (requestData.data as any).max_connections = params.max_connections; } // Build query parameters const queryParams = { 'return_offers': params.return_offers.toString(), 'supplier_timeout': params.supplier_timeout.toString() }; // Make the API call console.log(`Creating offer request with data: ${JSON.stringify(requestData)}`); const response = await this.client.post('/offer_requests', requestData, { params: queryParams }); const responseData = response.data; const requestId = responseData.data.id; const offers = responseData.data.offers || []; console.log(`Created offer request with ID: ${requestId}`); console.log(`Received ${offers.length} offers`); // Format the response const formattedResponse: FormattedOfferResponse = { request_id: requestId, offers: [] }; // Process offers (limit to 50 to manage response size) formattedResponse.offers = offers.slice(0, 50).map((offer: any) => { const formattedOffer: FormattedOffer = { offer_id: offer.id, price: { amount: offer.total_amount, currency: offer.total_currency, }, slices: [] }; // Process slices if (offer.slices) { formattedOffer.slices = offer.slices.map((slice: any) => { const segments = slice.segments || []; if (segments.length === 0) { return { origin: slice.origin.iata_code, destination: slice.destination.iata_code, departure: '', arrival: '', duration: slice.duration || '', carrier: '', stops: 0, stops_description: 'No segments available', connections: [] }; } const sliceDetails: SliceDetails = { origin: slice.origin.iata_code, destination: slice.destination.iata_code, departure: segments[0].departing_at || '', arrival: segments[segments.length - 1].arriving_at || '', duration: slice.duration || '', carrier: segments[0].marketing_carrier?.name || '', stops: segments.length - 1, stops_description: segments.length === 1 ? 'Non-stop' : `${segments.length - 1} stop${segments.length - 1 > 1 ? 's' : ''}`, connections: [] }; // Add connection information if (segments.length > 1) { for (let i = 0; i < segments.length - 1; i++) { sliceDetails.connections.push({ airport: segments[i].destination?.iata_code || '', arrival: segments[i].arriving_at || '', departure: segments[i + 1].departing_at || '', duration: segments[i + 1].duration || '' }); } } return sliceDetails; }); } return formattedOffer; }); return formattedResponse; } catch (error) { console.error(`Error creating offer request: ${error}`); throw error; } }