Skip to main content
Glama
hrz8
by hrz8

search_flights

Find available flights using origin/destination codes, dates, and passenger details. Requires booking session initialization first to obtain authentication token for flight search functionality.

Instructions

Perform a flight search based on search criteria. This operation required 'initialize_booking_session' to be exexcuted first to start the session.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
requestBodyYesFlight search parameters for finding available flights. Can be identical to initialization parameters or refined based on customer preferences.
session-tokenYesRequired authentication token obtained from the initialization step. This token is generated during booking initialization and returned in the response headers (look for "Session-Token" header). The token maintains booking context and enables flight search functionality. WITHOUT this token, flight searches will fail.

Implementation Reference

  • Defines and registers the 'search_flights' tool including its metadata, input schema reference, API endpoint, parameters, security, and custom serializer that implements the core response processing logic for displaying flight search results.
    'search_flights', { name: 'search_flights', description: `Perform a flight search based on search criteria. This operation required 'initialize_booking_session' to be exexcuted first to start the session.`, inputSchema: FlightSearchSchema, method: 'post', pathTemplate: '/flight-search/flights', executionParameters: [ { name: 'session-token', in: 'header', }, ], requestBodyContentType: 'application/json', securityRequirements: [ { HeaderApiToken: [], HeaderApimSubscriptionKey: [], HeaderApiVersion: [], }, ], serializer: (response: AxiosResponse<FlightSearchResponse>): string => { const { data: responseData } = response; const { data, dictionaries } = responseData; const { airBoundGroups } = data; let output = 'FLIGHT SEARCH RESULTS\n'; output += '='.repeat(80) + '\n\n'; if (!airBoundGroups || airBoundGroups.length === 0) { return output + 'No flights found matching your criteria.\n'; } airBoundGroups.forEach((group, groupIdx) => { const { boundDetails, airBounds } = group; const { origin, destination, duration, segments, isFastestBound } = boundDetails; const originLoc = dictionaries.location[origin.airportCode]; const destLoc = dictionaries.location[destination.airportCode]; if (!originLoc || !destLoc) { output += `Warning: Location information not available for group ${groupIdx + 1}\n\n`; return; } if (!segments || segments.length === 0) { output += `Warning: No segment information for group ${groupIdx + 1}\n\n`; return; } const firstSegment = segments[0]!; const flightDetails = dictionaries.flight[firstSegment.flightId]; if (!flightDetails) { output += `Warning: Flight details not available for group ${groupIdx + 1}\n\n`; return; } const allPrices = airBounds.map((ab) => ab.prices.totalPrice.total); const minPrice = Math.min(...allPrices); const maxPrice = Math.max(...allPrices); const currency = airBounds[0]?.prices.totalPrice.original.currencyCode || 'MYR'; // Extract flight number for the header const mainFlightNumber = flightDetails.flightDesignator.marketing.flightNumber; const mainAirlineCode = flightDetails.flightDesignator.marketing.airlineCode; output += `OPTION ${groupIdx + 1}${isFastestBound ? ' (FASTEST)' : ''}\n`; output += `Flight: ${mainAirlineCode}${mainFlightNumber}\n`; output += `Route: ${originLoc.cityName} (${origin.airportCode}) -> ${destLoc.cityName} (${destination.airportCode})\n`; output += `Departure: ${formatDate(flightDetails.departure.dateTime)} at ${formatTime( flightDetails.departure.dateTime, )}\n`; output += `Duration: ${formatDuration(duration)}\n`; output += `Price Range: ${formatPrice(minPrice, currency)} - ${formatPrice(maxPrice, currency)}\n`; output += '\nFlight Details:\n'; segments.forEach((seg, segIdx) => { const flight = dictionaries.flight[seg.flightId]; if (flight) { const airline = dictionaries.airline[flight.flightDesignator.marketing.airlineCode]; const flightNum = flight.flightDesignator.marketing.flightNumber; const operatingAirline = dictionaries.airline[flight.flightDesignator.operating.airlineCode]; output += ` ${segIdx + 1}. ${airline} ${flightNum}`; // Show if operated by different airline (code share) if ( flight.flightDesignator.marketing.airlineCode !== flight.flightDesignator.operating.airlineCode ) { output += ` (operated by ${operatingAirline})`; } output += `\n Aircraft: ${flight.aircraftName}\n`; output += ` ${flight.departure.locationCode}`; if (flight.departure.terminal) { output += ` T${flight.departure.terminal}`; } output += ` ${formatTime(flight.departure.dateTime)}`; output += ` -> ${flight.arrival.locationCode}`; if (flight.arrival.terminal) { output += ` T${flight.arrival.terminal}`; } output += ` ${formatTime(flight.arrival.dateTime)}`; if (seg.arrivalDaysDifference) { output += ` +${seg.arrivalDaysDifference}d`; } output += `\n`; } }); const econFares = airBounds.filter((ab) => { const ff = dictionaries.fareFamilyWithServices[ab.fareFamilyCode]; return ff?.cabin === 'eco'; }); const busFares = airBounds.filter((ab) => { const ff = dictionaries.fareFamilyWithServices[ab.fareFamilyCode]; return ff?.cabin === 'business'; }); if (econFares.length > 0) { output += '\nEconomy Class Options:\n'; econFares.forEach((fare) => { const isRecommended = fare.extraProperties?.isRecommended; const isCheapest = fare.isCheapestOffer; const price = formatPrice(fare.prices.totalPrice.total, currency); const fareFamily = fare.fareFamilyCode; const availability = fare.availabilityDetails?.[0]; if (!availability) { return; } output += ` ${isRecommended ? '[RECOMMENDED] ' : isCheapest ? '[CHEAPEST] ' : ''}${fareFamily}: ${price}`; output += ` | Class: ${availability.bookingClass}`; if (availability.seatLeft) { output += ` | ${availability.seatLeft} seats left`; } output += `\n AirBoundID: ${fare.airBoundId}\n`; }); } if (busFares.length > 0) { output += '\nBusiness Class Options:\n'; busFares.forEach((fare) => { const isRecommended = fare.extraProperties?.isRecommended; const price = formatPrice(fare.prices.totalPrice.total, currency); const fareFamily = fare.fareFamilyCode; const availability = fare.availabilityDetails?.[0]; if (!availability) { return; } output += ` ${isRecommended ? '[RECOMMENDED] ' : ''}${fareFamily}: ${price}`; output += ` | Class: ${availability.bookingClass}`; if (availability.seatLeft) { output += ` | ${availability.seatLeft} seats left`; } output += `\n AirBoundID: ${fare.airBoundId}\n`; }); } output += '\n' + '-'.repeat(80) + '\n\n'; }); output += 'To select a flight, use the create_cart tool with the desired AirBoundID(s)\n'; return output; }, }, ],
  • Zod schema for validating inputs to search_flights tool: requires session-token header and requestBody with itineraries, travelers, fare families, etc.
    export const FlightSearchSchema = z.object({ 'session-token': z.string() .min(1) .describe('Required authentication token obtained from the initialization step. This token is generated during booking initialization and returned in the response headers (look for "Session-Token" header). The token maintains booking context and enables flight search functionality. WITHOUT this token, flight searches will fail.'), requestBody: FlightSearchBodySchema .describe('Flight search parameters for finding available flights. Can be identical to initialization parameters or refined based on customer preferences.'), }).describe('STEP 2: Perform actual flight search using session token from initialization. This endpoint searches for available flights matching the criteria and returns flight options with pricing and schedules.');
  • Core FlightSearchBodySchema defining the request body structure for flight searches, including itineraries (origin/dest/date), passengers, fare families, and flow type. Referenced by FlightSearchSchema.
    const FlightSearchBodySchema = z .object({ commercialFareFamilies: z.array(z.string()) .min(1) .describe('Array of fare family codes to filter search results. Common codes: CFFECO (Economy), CFFBUS (Business), CFFFIR (First). Use airline-specific codes for targeted searches.'), itineraries: z.array(ItinerarySegment) .min(1) .max(10) .describe('Flight segments defining the journey. Single segment = one-way, two segments = round-trip. Each segment represents one flight leg of the complete journey.'), selectedBoundId: z.string() .optional() .describe('Optional identifier for pre-selected outbound flight in round-trip bookings. Used when customer has already chosen their outbound flight and is now selecting return options.'), flowCode: FlowCode .default('Revenue') .describe('Booking flow context that determines available options and pricing logic'), travelers: z.array(Traveler) .min(1) .max(9) .describe('List of all passengers for the booking. Each traveler object represents one person. Total count affects pricing and availability. Maximum 9 passengers per booking.'), }) .describe('Flight search request schema for airline booking systems. Supports one-way and round-trip searches with multiple passenger types and fare family filtering.');
  • Registers all tools from the tools map (including search_flights) with the MCP server for listTools and callTool requests, delegating execution to executeApiTool.
    export function registerTools(server: Server): void { server.setRequestHandler(ListToolsRequestSchema, async () => { const toolsForClient: Tool[] = []; for (const def of Array.from(tools.values())) { toolsForClient.push({ name: def.name, description: def.description, inputSchema: zodToMcpJsonSchema(def.inputSchema), }); } return { tools: toolsForClient, }; }); server.setRequestHandler( CallToolRequestSchema, async (request: CallToolRequest): Promise<CallToolResult> => { const { name: toolName, arguments: toolArgs } = request.params; console.info(`Attempt to use custom tool: ${toolName}`); const toolDefinition = tools.get(toolName); if (!toolDefinition) { return { content: [ { type: 'text', text: `Error: Unknown tool requested: ${toolName}`, }, ], }; } return await executeApiTool( toolName, toolDefinition, toolArgs ?? {}, securitySchemes, ); }, ); }
  • Generic tool executor used by all tools including search_flights: validates args with schema, builds HTTP request to the API endpoint specified in tool def, applies security headers/tokens, executes axios request, and formats response using the tool-specific serializer.
    export async function executeApiTool( toolName: string, definition: McpToolDefinition, toolArgs: Record<string, unknown>, securityRequirementDictionaries: Record<string, SecurityScheme>, ): Promise<CallToolResult> { // 1. Validate arguments const validation = validateToolArguments(toolName, definition, toolArgs); if (!validation.success) { return validation.result; } try { // 2. Build request configuration const baseUrl = DSP_BOOKING_BASE_URL; const requestConfig = buildRequestConfig(definition, validation.data); // 3. Validate and apply security const securityContext = validateSecurity(definition, securityRequirementDictionaries); if (!securityContext.isValid) { console.warn(`Tool '${toolName}' ${securityContext.errorMessage}`); return { content: [ { type: 'text', text: `Internal error during tool setup: '${toolName}'`, }, ], }; } if (securityContext.appliedSecurity) { await applySecurity( requestConfig.headers, securityContext.appliedSecurity, securityRequirementDictionaries, ); } // 4. Create axios configuration const axiosConfig: AxiosRequestConfig = { method: definition.method.toUpperCase(), url: baseUrl + requestConfig.urlPath, params: requestConfig.queryParams, headers: requestConfig.headers, ...(requestConfig.requestBodyData !== undefined && { data: requestConfig.requestBodyData }), }; // 5. Execute request console.info(`Executing tool "${toolName}": ${axiosConfig.method} ${axiosConfig.url}`); const response = await axios(axiosConfig); // 6. Format and return response - pass definition instead of toolName return formatResponse(response, definition); } catch (error) { return formatError(toolName, error); } }

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/hrz8/mcp-openapi'

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