iflow-mcp_smamidipaka6-google-flights-mcp-server 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flights.py +517 -0
- iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/METADATA +303 -0
- iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/RECORD +7 -0
- iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/WHEEL +5 -0
- iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/licenses/LICENSE +21 -0
- iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/top_level.txt +1 -0
flights.py
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
import httpx
|
|
3
|
+
from mcp.server.fastmcp import FastMCP
|
|
4
|
+
|
|
5
|
+
from fast_flights import FlightData, Passengers, Result, get_flights, search_airport
|
|
6
|
+
from dataclasses import asdict
|
|
7
|
+
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# initialize the MCP server
|
|
12
|
+
mcp = FastMCP("flights")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Helper Functions
|
|
16
|
+
|
|
17
|
+
def format_flight_info(flight_data, origin_airport, destination_airport):
|
|
18
|
+
"""
|
|
19
|
+
Formats flight information into a human-readable string.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
flight_data: Dictionary containing flight information
|
|
23
|
+
origin_airport: Name of Origin airport city and IATA code (ex: "Seattle (SEA)")
|
|
24
|
+
destination_airport: Name of Destination airport city and IATA code (ex: "Tokyo (HND)")
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Formatted string describing the flight
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
duration_parts = flight_data['duration'].split()
|
|
31
|
+
|
|
32
|
+
if len(duration_parts) == 4:
|
|
33
|
+
duration_formatted = f"{duration_parts[0]} hours and {duration_parts[2]} minutes"
|
|
34
|
+
else:
|
|
35
|
+
duration_formatted = flight_data['duration']
|
|
36
|
+
|
|
37
|
+
# Reformat departure and arrival dates
|
|
38
|
+
def expand_date(date_str):
|
|
39
|
+
# Map abbreviated month and day
|
|
40
|
+
month_map = {
|
|
41
|
+
'Jan': 'January', 'Feb': 'February', 'Mar': 'March',
|
|
42
|
+
'Apr': 'April', 'May': 'May', 'Jun': 'June',
|
|
43
|
+
'Jul': 'July', 'Aug': 'August', 'Sep': 'September',
|
|
44
|
+
'Oct': 'October', 'Nov': 'November', 'Dec': 'December'
|
|
45
|
+
}
|
|
46
|
+
day_map = {'Mon': 'Monday', 'Tue': 'Tuesday', 'Wed': 'Wednesday',
|
|
47
|
+
'Thu': 'Thursday', 'Fri': 'Friday', 'Sat': 'Saturday',
|
|
48
|
+
'Sun': 'Sunday'}
|
|
49
|
+
|
|
50
|
+
parts = date_str.split()
|
|
51
|
+
time = f"{parts[0]} {parts[1]}" # "9:40 AM"
|
|
52
|
+
|
|
53
|
+
# Handle the day abbreviation (removing the comma)
|
|
54
|
+
day_abbr = parts[3].rstrip(',') # "Sat" (removing comma from "Sat,")
|
|
55
|
+
month_abbr = parts[4] # "Apr"
|
|
56
|
+
day = parts[5] # "5"
|
|
57
|
+
|
|
58
|
+
full_day = day_map.get(day_abbr, day_abbr)
|
|
59
|
+
full_month = month_map.get(month_abbr, month_abbr)
|
|
60
|
+
|
|
61
|
+
# Add ordinal suffix to the day
|
|
62
|
+
day_with_suffix = day + ('th' if not day.endswith(('1', '2', '3')) or day.endswith(('11', '12', '13')) else
|
|
63
|
+
('st' if day.endswith('1') else
|
|
64
|
+
('nd' if day.endswith('2') else
|
|
65
|
+
('rd' if day.endswith('3') else 'th'))))
|
|
66
|
+
|
|
67
|
+
return f"{time} on {full_day}, {full_month} {day_with_suffix}"
|
|
68
|
+
|
|
69
|
+
# Determine best flight qualifier
|
|
70
|
+
best_flight_qualifier = "considered one of the best options by Google Flights" if flight_data['is_best'] else "an available option"
|
|
71
|
+
|
|
72
|
+
# Handle potential None or empty values
|
|
73
|
+
stops = flight_data["stops"]
|
|
74
|
+
stops_text = f"{stops} stop{'s' if stops != 1 else ''}" if stops > 0 else "non-stop"
|
|
75
|
+
|
|
76
|
+
formatted_string = (
|
|
77
|
+
f"This flight departs at {expand_date(flight_data['departure'])} from {origin_airport}, local time, "
|
|
78
|
+
f"and arrives at {expand_date(flight_data['arrival'])} in {destination_airport}, local time. "
|
|
79
|
+
f"The flight is operated by {flight_data['name']} and has a duration of {duration_formatted} "
|
|
80
|
+
f"with {stops_text} in between. "
|
|
81
|
+
f"And it's price is {flight_data['price']} and is {best_flight_qualifier}!"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return formatted_string
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Main Functions
|
|
91
|
+
|
|
92
|
+
@mcp.tool()
|
|
93
|
+
async def get_general_flights_info(origin: str, destination: str, departure_date: str,
|
|
94
|
+
trip_type: str = "one-way", seat: str = "economy",
|
|
95
|
+
adults: int = 1, children: int = 0, infants_in_seat: int = 0, infants_on_lap: int = 0,
|
|
96
|
+
n_flights: int = 40) -> list[str]:
|
|
97
|
+
""" Get general/comprehensive flight information for N flights for a given origin, destination, and departure date. If the user wants to do a round-trip,
|
|
98
|
+
you will need to make two one-way trip calls.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
origin (str): The origin airport IATA code (ex: "ATL", "SCL", "JFK").
|
|
102
|
+
destination (str): The destination airport IATA code (ex: "DTW", "ICN", "LIR").
|
|
103
|
+
departure_date (str): The departure date in YYYY-MM-DD format.
|
|
104
|
+
|
|
105
|
+
trip_type (str, optional): The type of trip ("one-way" or "round-trip" only). Defaults to "one-way".
|
|
106
|
+
seat (str, optional): The type of seat ("economy", "premium-economy", "business", or "first" only). Defaults to "economy".
|
|
107
|
+
adults (int, optional): The number of adults. Defaults to 1.
|
|
108
|
+
children (int, optional): The number of children. Defaults to 0.
|
|
109
|
+
infants_in_seat (int, optional): The number of infants in a seat. Defaults to 0.
|
|
110
|
+
infants_lap (int, optional): The number of infants on a lap. Defaults to 0.
|
|
111
|
+
|
|
112
|
+
n_flights (int, optional): The number of flights to return. Defaults to 25.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
list[str]: A list of flight information strings.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
if (len(origin) != 3 or len(destination) != 3):
|
|
119
|
+
return "Origin and destination must be 3 characters."
|
|
120
|
+
|
|
121
|
+
if (len(departure_date) != 10 or departure_date[4] != '-' or departure_date[7] != '-'):
|
|
122
|
+
return "Departure date must be in YYYY-MM-DD format."
|
|
123
|
+
|
|
124
|
+
if (trip_type != "one-way" and trip_type != "round-trip"):
|
|
125
|
+
return "Trip type must be either 'one-way' or 'round-trip'."
|
|
126
|
+
|
|
127
|
+
if (seat != "economy" and seat != "premium-economy" and seat != "business" and seat != "first"):
|
|
128
|
+
return "Seat type must be either 'economy', 'premium-economy', 'business', or 'first'."
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
|
|
133
|
+
# Make API call to Google Flights via fast-flights
|
|
134
|
+
|
|
135
|
+
flight_data_input = [FlightData(date=departure_date, from_airport=origin, to_airport=destination)]
|
|
136
|
+
|
|
137
|
+
passengers_input = Passengers(adults=adults, children=children, infants_in_seat=infants_in_seat, infants_on_lap=infants_on_lap)
|
|
138
|
+
|
|
139
|
+
result: Result = get_flights(
|
|
140
|
+
flight_data=flight_data_input,
|
|
141
|
+
trip=trip_type,
|
|
142
|
+
seat=seat,
|
|
143
|
+
passengers=passengers_input,
|
|
144
|
+
fetch_mode="fallback"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
result = asdict(result)
|
|
148
|
+
|
|
149
|
+
if not result or "flights" not in result:
|
|
150
|
+
return ["No flight data available for the specified route and dates."]
|
|
151
|
+
|
|
152
|
+
current_price = result["current_price"]
|
|
153
|
+
all_flights = result["flights"]
|
|
154
|
+
|
|
155
|
+
if not all_flights:
|
|
156
|
+
return ["No flights found for the specified route and dates."]
|
|
157
|
+
|
|
158
|
+
top_n_flights = all_flights[0: min(n_flights, len(all_flights))]
|
|
159
|
+
|
|
160
|
+
flight_info = []
|
|
161
|
+
|
|
162
|
+
origin_airport = origin
|
|
163
|
+
destination_airport = destination
|
|
164
|
+
|
|
165
|
+
for flight in top_n_flights:
|
|
166
|
+
flight_info.append(format_flight_info(flight, origin_airport, destination_airport))
|
|
167
|
+
|
|
168
|
+
output = [f"The current overall flight prices for this route and time are: {str(current_price)}."] + flight_info
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
return output
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
except httpx.RequestError:
|
|
175
|
+
return ["Unable to connect to the flight search service. Please try again later."]
|
|
176
|
+
|
|
177
|
+
except ValueError as e:
|
|
178
|
+
return [f"Invalid data received: {str(e)}"]
|
|
179
|
+
|
|
180
|
+
except Exception as e:
|
|
181
|
+
return [f"An unexpected error occurred while searching for flights: {str(e)}"]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@mcp.tool()
|
|
186
|
+
async def get_cheapest_flights(origin: str, destination: str, departure_date: str,
|
|
187
|
+
trip_type: str = "one-way", seat: str = "economy",
|
|
188
|
+
adults: int = 1, children: int = 0, infants_in_seat: int = 0, infants_on_lap: int = 0) -> list[str]:
|
|
189
|
+
|
|
190
|
+
""" Get the cheapest flight information for a given origin, destination, and departure date. If the user wants to do a round-trip,
|
|
191
|
+
you will need to make two one-way trip calls.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
origin (str): The origin airport IATA code (ex: "ATL", "SCL", "JFK").
|
|
195
|
+
destination (str): The destination airport IATA code (ex: "DTW", "ICN", "LIR").
|
|
196
|
+
departure_date (str): The departure date in YYYY-MM-DD format.
|
|
197
|
+
|
|
198
|
+
trip_type (str, optional): The type of trip ("one-way" or "round-trip" only). Defaults to "one-way".
|
|
199
|
+
seat (str, optional): The type of seat ("economy", "premium-economy", "business", or "first" only). Defaults to "economy".
|
|
200
|
+
adults (int, optional): The number of adults. Defaults to 1.
|
|
201
|
+
children (int, optional): The number of children. Defaults to 0.
|
|
202
|
+
infants_in_seat (int, optional): The number of infants in a seat. Defaults to 0.
|
|
203
|
+
infants_lap (int, optional): The number of infants on a lap. Defaults to 0.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
list[str]: A list of flight information strings.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
if (len(origin) != 3 or len(destination) != 3):
|
|
210
|
+
return "Origin and destination must be 3 characters."
|
|
211
|
+
|
|
212
|
+
if (len(departure_date) != 10 or departure_date[4] != '-' or departure_date[7] != '-'):
|
|
213
|
+
return "Departure date must be in YYYY-MM-DD format."
|
|
214
|
+
|
|
215
|
+
if (trip_type != "one-way" and trip_type != "round-trip"):
|
|
216
|
+
return "Trip type must be either 'one-way' or 'round-trip'."
|
|
217
|
+
|
|
218
|
+
if (seat != "economy" and seat != "premium-economy" and seat != "business" and seat != "first"):
|
|
219
|
+
return "Seat type must be either 'economy', 'premium-economy', 'business', or 'first'."
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
# Make API call to Google Flights via fast-flights
|
|
223
|
+
|
|
224
|
+
flight_data_input = [FlightData(date=departure_date, from_airport=origin, to_airport=destination)]
|
|
225
|
+
passengers_input = Passengers(adults=adults, children=children, infants_in_seat=infants_in_seat, infants_on_lap=infants_on_lap)
|
|
226
|
+
|
|
227
|
+
result: Result = get_flights(
|
|
228
|
+
flight_data=flight_data_input,
|
|
229
|
+
trip=trip_type,
|
|
230
|
+
seat=seat,
|
|
231
|
+
passengers=passengers_input,
|
|
232
|
+
fetch_mode="fallback"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
result = asdict(result)
|
|
236
|
+
|
|
237
|
+
if not result or "flights" not in result:
|
|
238
|
+
return ["No flight data available for the specified route and dates."]
|
|
239
|
+
|
|
240
|
+
all_flights = result["flights"]
|
|
241
|
+
|
|
242
|
+
if not all_flights:
|
|
243
|
+
return ["No flights found for the specified route and dates."]
|
|
244
|
+
|
|
245
|
+
def get_price_value(flight):
|
|
246
|
+
|
|
247
|
+
price_str = flight['price']
|
|
248
|
+
|
|
249
|
+
# Remove $ and any commas from the price string
|
|
250
|
+
price_str = price_str.replace('$', '')
|
|
251
|
+
price_str = price_str.replace(',', '')
|
|
252
|
+
|
|
253
|
+
# Convert to decimal number
|
|
254
|
+
return float(price_str)
|
|
255
|
+
|
|
256
|
+
price_sorted_flights = sorted(all_flights, key=get_price_value)
|
|
257
|
+
|
|
258
|
+
top_n_flights = price_sorted_flights[0: min(30, len(price_sorted_flights))]
|
|
259
|
+
|
|
260
|
+
flight_info = []
|
|
261
|
+
|
|
262
|
+
origin_airport = origin
|
|
263
|
+
destination_airport = destination
|
|
264
|
+
|
|
265
|
+
for flight in top_n_flights:
|
|
266
|
+
flight_info.append(format_flight_info(flight, origin_airport, destination_airport))
|
|
267
|
+
|
|
268
|
+
output = ["Here are the cheapest flights for this route and time: "] + flight_info
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
return output
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
except httpx.RequestError:
|
|
276
|
+
return ["Unable to connect to the flight search service. Please try again later."]
|
|
277
|
+
|
|
278
|
+
except ValueError as e:
|
|
279
|
+
return [f"Invalid data received: {str(e)}"]
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
return [f"An unexpected error occurred while searching for flights: {str(e)}"]
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@mcp.tool()
|
|
286
|
+
async def get_best_flights(origin: str, destination: str, departure_date: str,
|
|
287
|
+
trip_type: str = "one-way", seat: str = "economy",
|
|
288
|
+
adults: int = 1, children: int = 0, infants_in_seat: int = 0, infants_on_lap: int = 0) -> list[str]:
|
|
289
|
+
|
|
290
|
+
""" Get the best flights as determined by Google Flights for a given origin, destination, and departure date. If the user wants to do a round-trip,
|
|
291
|
+
you will need to make two one-way trip calls.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
origin (str): The origin airport IATA code (ex: "ATL", "SCL", "JFK").
|
|
295
|
+
destination (str): The destination airport IATA code (ex: "DTW", "ICN", "LIR").
|
|
296
|
+
departure_date (str): The departure date in YYYY-MM-DD format.
|
|
297
|
+
|
|
298
|
+
trip_type (str, optional): The type of trip ("one-way" or "round-trip" only). Defaults to "one-way".
|
|
299
|
+
seat (str, optional): The type of seat ("economy", "premium-economy", "business", or "first" only). Defaults to "economy".
|
|
300
|
+
adults (int, optional): The number of adults. Defaults to 1.
|
|
301
|
+
children (int, optional): The number of children. Defaults to 0.
|
|
302
|
+
infants_in_seat (int, optional): The number of infants in a seat. Defaults to 0.
|
|
303
|
+
infants_lap (int, optional): The number of infants on a lap. Defaults to 0.
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
list[str]: A list of flight information strings.
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
if (len(origin) != 3 or len(destination) != 3):
|
|
310
|
+
return "Origin and destination must be 3 characters."
|
|
311
|
+
|
|
312
|
+
if (len(departure_date) != 10 or departure_date[4] != '-' or departure_date[7] != '-'):
|
|
313
|
+
return "Departure date must be in YYYY-MM-DD format."
|
|
314
|
+
|
|
315
|
+
if (trip_type != "one-way" and trip_type != "round-trip"):
|
|
316
|
+
return "Trip type must be either 'one-way' or 'round-trip'."
|
|
317
|
+
|
|
318
|
+
if (seat != "economy" and seat != "premium-economy" and seat != "business" and seat != "first"):
|
|
319
|
+
return "Seat type must be either 'economy', 'premium-economy', 'business', or 'first'."
|
|
320
|
+
|
|
321
|
+
try:
|
|
322
|
+
# Make API call to Google Flights via fast-flights
|
|
323
|
+
|
|
324
|
+
flight_data_input = [FlightData(date=departure_date, from_airport=origin, to_airport=destination)]
|
|
325
|
+
|
|
326
|
+
passengers_input = Passengers(adults=adults, children=children, infants_in_seat=infants_in_seat, infants_on_lap=infants_on_lap)
|
|
327
|
+
|
|
328
|
+
result: Result = get_flights(
|
|
329
|
+
flight_data=flight_data_input,
|
|
330
|
+
trip=trip_type,
|
|
331
|
+
seat=seat,
|
|
332
|
+
passengers=passengers_input,
|
|
333
|
+
fetch_mode="fallback"
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
result = asdict(result)
|
|
337
|
+
|
|
338
|
+
if not result or "flights" not in result:
|
|
339
|
+
return ["No flight data available for the specified route and dates."]
|
|
340
|
+
|
|
341
|
+
all_flights = result["flights"]
|
|
342
|
+
|
|
343
|
+
if not all_flights:
|
|
344
|
+
return ["No flights found for the specified route and dates."]
|
|
345
|
+
|
|
346
|
+
best_flights = []
|
|
347
|
+
|
|
348
|
+
for flight in all_flights:
|
|
349
|
+
if (flight['is_best']):
|
|
350
|
+
best_flights.append(flight)
|
|
351
|
+
|
|
352
|
+
if not best_flights:
|
|
353
|
+
return ["No best flights found for the specified route and dates."]
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
top_n_flights = best_flights[0: min(30, len(best_flights))]
|
|
357
|
+
|
|
358
|
+
flight_info = []
|
|
359
|
+
|
|
360
|
+
origin_airport = origin
|
|
361
|
+
destination_airport = destination
|
|
362
|
+
|
|
363
|
+
for flight in top_n_flights:
|
|
364
|
+
flight_info.append(format_flight_info(flight, origin_airport, destination_airport))
|
|
365
|
+
|
|
366
|
+
output = ["Here are the best flights for this route and time: "] + flight_info
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
return output
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
except httpx.RequestError:
|
|
374
|
+
return ["Unable to connect to the flight search service. Please try again later."]
|
|
375
|
+
|
|
376
|
+
except ValueError as e:
|
|
377
|
+
return [f"Invalid data received: {str(e)}"]
|
|
378
|
+
|
|
379
|
+
except Exception as e:
|
|
380
|
+
return [f"An unexpected error occurred while searching for flights: {str(e)}"]
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@mcp.tool()
|
|
385
|
+
async def get_time_filtered_flights(state: str, target_time_str: str, origin: str, destination: str, departure_date: str,
|
|
386
|
+
trip_type: str = "one-way", seat: str = "economy",
|
|
387
|
+
adults: int = 1, children: int = 0, infants_in_seat: int = 0, infants_on_lap: int = 0) -> list[str]:
|
|
388
|
+
|
|
389
|
+
""" Get time-filtered flight information based on the user's preferences for before or after a certain time for a given origin, destination, and departure date. If the user wants to do a round-trip,
|
|
390
|
+
you will need to make two one-way trip calls.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
state (str): The state of the flight ("before" or "after" only). For before, we do before the target time. For after, we do on or after the target time.
|
|
394
|
+
target_time_str (str): The target time in HH:MM AM/PM format (ex: "7:00 PM").
|
|
395
|
+
origin (str): The origin airport IATA code (ex: "ATL", "SCL", "JFK").
|
|
396
|
+
destination (str): The destination airport IATA code (ex: "DTW", "ICN", "LIR").
|
|
397
|
+
departure_date (str): The departure date in YYYY-MM-DD format.
|
|
398
|
+
|
|
399
|
+
trip_type (str, optional): The type of trip ("one-way" or "round-trip" only). Defaults to "one-way".
|
|
400
|
+
seat (str, optional): The type of seat ("economy", "premium-economy", "business", or "first" only). Defaults to "economy".
|
|
401
|
+
adults (int, optional): The number of adults. Defaults to 1.
|
|
402
|
+
children (int, optional): The number of children. Defaults to 0.
|
|
403
|
+
infants_in_seat (int, optional): The number of infants in a seat. Defaults to 0.
|
|
404
|
+
infants_lap (int, optional): The number of infants on a lap. Defaults to 0.
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
list[str]: A list of flight information strings.
|
|
408
|
+
"""
|
|
409
|
+
|
|
410
|
+
if (len(origin) != 3 or len(destination) != 3):
|
|
411
|
+
return "Origin and destination must be 3 characters."
|
|
412
|
+
|
|
413
|
+
if (len(departure_date) != 10 or departure_date[4] != '-' or departure_date[7] != '-'):
|
|
414
|
+
return "Departure date must be in YYYY-MM-DD format."
|
|
415
|
+
|
|
416
|
+
if (trip_type != "one-way" and trip_type != "round-trip"):
|
|
417
|
+
return "Trip type must be either 'one-way' or 'round-trip'."
|
|
418
|
+
|
|
419
|
+
if (seat != "economy" and seat != "premium-economy" and seat != "business" and seat != "first"):
|
|
420
|
+
return "Seat type must be either 'economy', 'premium-economy', 'business', or 'first'."
|
|
421
|
+
|
|
422
|
+
if (state != "before" and state != "after"):
|
|
423
|
+
return "State must be either 'before' or 'after'."
|
|
424
|
+
|
|
425
|
+
try:
|
|
426
|
+
# Validate time format first
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
target_time = datetime.strptime(target_time_str, '%I:%M %p').time()
|
|
430
|
+
except ValueError:
|
|
431
|
+
return ["Invalid time format. Please use HH:MM AM/PM format (e.g., '7:00 PM')."]
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
# Make API call to Google Flights via fast-flights
|
|
435
|
+
flight_data_input = [FlightData(date=departure_date, from_airport=origin, to_airport=destination)]
|
|
436
|
+
|
|
437
|
+
passengers_input = Passengers(adults=adults, children=children, infants_in_seat=infants_in_seat, infants_on_lap=infants_on_lap)
|
|
438
|
+
|
|
439
|
+
result: Result = get_flights(
|
|
440
|
+
flight_data=flight_data_input,
|
|
441
|
+
trip=trip_type,
|
|
442
|
+
seat=seat,
|
|
443
|
+
passengers=passengers_input,
|
|
444
|
+
fetch_mode="fallback"
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
result = asdict(result)
|
|
448
|
+
|
|
449
|
+
if not result or "flights" not in result:
|
|
450
|
+
return ["No flight data available for the specified route and dates."]
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
all_flights = result["flights"]
|
|
454
|
+
|
|
455
|
+
if not all_flights:
|
|
456
|
+
return ["No flights found for the specified route and dates."]
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
valid_flights = []
|
|
460
|
+
|
|
461
|
+
for flight in all_flights:
|
|
462
|
+
|
|
463
|
+
parts = flight['departure'].split(" ")
|
|
464
|
+
time_str = parts[0] + " " + parts[1]
|
|
465
|
+
|
|
466
|
+
flight_time = datetime.strptime(time_str, '%I:%M %p').time()
|
|
467
|
+
|
|
468
|
+
if (state == "before"):
|
|
469
|
+
if (flight_time < target_time):
|
|
470
|
+
valid_flights.append(flight)
|
|
471
|
+
elif (state == "after"):
|
|
472
|
+
if (flight_time >= target_time):
|
|
473
|
+
valid_flights.append(flight)
|
|
474
|
+
|
|
475
|
+
if not valid_flights:
|
|
476
|
+
return [f"No flights found {state} {target_time_str} for the specified route and dates."]
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
top_n_flights = valid_flights[0: min(30, len(valid_flights))]
|
|
480
|
+
|
|
481
|
+
flight_info = []
|
|
482
|
+
|
|
483
|
+
origin_airport = origin
|
|
484
|
+
destination_airport = destination
|
|
485
|
+
|
|
486
|
+
for flight in top_n_flights:
|
|
487
|
+
flight_info.append(format_flight_info(flight, origin_airport, destination_airport))
|
|
488
|
+
|
|
489
|
+
context_str = f"Here are the time-filtered flights {('before' if state == 'before' else 'on or after')} {target_time_str}: "
|
|
490
|
+
|
|
491
|
+
output = [context_str] + flight_info
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
return output
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
except httpx.RequestError:
|
|
498
|
+
return ["Unable to connect to the flight search service. Please try again later."]
|
|
499
|
+
|
|
500
|
+
except ValueError as e:
|
|
501
|
+
return [f"Invalid data received: {str(e)}"]
|
|
502
|
+
|
|
503
|
+
except Exception as e:
|
|
504
|
+
return [f"An unexpected error occurred while searching for flights: {str(e)}"]
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def main():
|
|
512
|
+
# Initialize and run the server
|
|
513
|
+
mcp.run(transport='stdio')
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
if __name__ == "__main__":
|
|
517
|
+
main()
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iflow-mcp_smamidipaka6-google-flights-mcp-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Google Flights MCP Server !!
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: fast-flights>=2.2
|
|
9
|
+
Requires-Dist: httpx>=0.28.1
|
|
10
|
+
Requires-Dist: mcp[cli]>=1.3.0
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# Google Flights MCP Server
|
|
14
|
+
|
|
15
|
+
A Model Context Protocol (MCP) server implementation that connects your Agents or LLMs to Google Flights data. Access flight information, find the cheapest options, filter by time restrictions, and get Google Flights' best recommendations!
|
|
16
|
+
|
|
17
|
+
## π Overview
|
|
18
|
+
|
|
19
|
+
This MCP server provides seamless access to Google Flights data, enabling your AI agents to:
|
|
20
|
+
|
|
21
|
+
- Retrieve **Comprehensive Flight Info**
|
|
22
|
+
- Find the **Cheapest Available Flights**
|
|
23
|
+
- Filter flights based on **Specific Time Constraints**
|
|
24
|
+
- Get Google Flights' recommended **Best Flights**
|
|
25
|
+
|
|
26
|
+
<br>
|
|
27
|
+
|
|
28
|
+
> **Note:** Currently, this tool only does one-ways (if you ask for a round-trip, it'll do two one-ways though!) as I built it as a fun pet project to learn about MCPs.
|
|
29
|
+
>
|
|
30
|
+
> If anyone actually finds this useful or wants me to, I can work on adding Round-Trip and Multi-City functionality!! Just raise a PR or [hit me up](https://sahit-personal-website.vercel.app/)!
|
|
31
|
+
|
|
32
|
+
## π₯ Usage & Demo
|
|
33
|
+
|
|
34
|
+
Just follow the Quick Start to set this up for Claude Desktop, Cursor, or another MCP Client and just ask away to find out about your desired flight info!!
|
|
35
|
+
|
|
36
|
+
[Insert Claude Desktop Demo Video]
|
|
37
|
+
|
|
38
|
+
## π οΈ Tools
|
|
39
|
+
|
|
40
|
+
### Available Functions/Tools
|
|
41
|
+
|
|
42
|
+
1. `get_general_flights_info()`: Retrieve comprehensive flight information for a given route
|
|
43
|
+
|
|
44
|
+
- Provides detailed flight details for up to 40 flights
|
|
45
|
+
- Returns a list of human-readable flight descriptions
|
|
46
|
+
|
|
47
|
+
2. `get_cheapest_flights()`: Find the most affordable flight options
|
|
48
|
+
|
|
49
|
+
- Sorts and returns flights by lowest price
|
|
50
|
+
- Includes current overall route pricing information
|
|
51
|
+
|
|
52
|
+
3. `get_best_flights()`: Get Google Flights' top recommended flights
|
|
53
|
+
|
|
54
|
+
- Identifies and returns flights marked as "best" by Google Flights
|
|
55
|
+
- Helps users find optimal flight choices
|
|
56
|
+
|
|
57
|
+
4. `get_time_filtered_flights()`: Filter flights by specific time constraints
|
|
58
|
+
- Search for flights before or after a target time
|
|
59
|
+
- Allows precise scheduling preferences
|
|
60
|
+
|
|
61
|
+
### Input Parameters
|
|
62
|
+
|
|
63
|
+
#### Required Parameters
|
|
64
|
+
|
|
65
|
+
- `origin: str` - Origin airport IATA code (e.g., "ATL", "SCL", "JFK")
|
|
66
|
+
|
|
67
|
+
- `destination: str` - Destination airport IATA code (e.g., "DTW", "ICN", "LIR")
|
|
68
|
+
- `departure_date: str` - Departure date in YYYY-MM-DD format
|
|
69
|
+
|
|
70
|
+
#### Optional Parameters
|
|
71
|
+
|
|
72
|
+
- `trip_type: str` - Trip type, either "one-way" or "round-trip" (default: "one-way")
|
|
73
|
+
|
|
74
|
+
- `seat: str` - Seat type: "economy", "premium-economy", "business", or "first" (default: "economy")
|
|
75
|
+
- `adults: int` - Number of adult passengers (default: 1)
|
|
76
|
+
- `children: int` - Number of child passengers (default: 0)
|
|
77
|
+
- `infants_in_seat: int` - Number of infants requiring a seat (default: 0)
|
|
78
|
+
- `infants_on_lap: int` - Number of infants traveling on a lap (default: 0)
|
|
79
|
+
|
|
80
|
+
#### Additional Parameters for Specific Functions
|
|
81
|
+
|
|
82
|
+
- `n_flights: int` - Number of flights to return (default: 40, only for `get_general_flights_info()`)
|
|
83
|
+
|
|
84
|
+
- `state: str` - Time filter state, either "before" or "after" (only for `get_time_filtered_flights()`)
|
|
85
|
+
- `target_time_str: str` - Target time in HH:MM AM/PM format (only for `get_time_filtered_flights()`)
|
|
86
|
+
|
|
87
|
+
## β‘ Quick Start
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
### Claude Desktop
|
|
91
|
+
|
|
92
|
+
1. Make sure you have the latest [Claude for Desktop](https://claude.ai/download) downloaded!
|
|
93
|
+
|
|
94
|
+
2. Clone This Repo
|
|
95
|
+
|
|
96
|
+
3. Install `uv` to set up our Python Environment
|
|
97
|
+
|
|
98
|
+
#### MacOS
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Check if uv is already installed
|
|
102
|
+
uv --version
|
|
103
|
+
|
|
104
|
+
# If not installed
|
|
105
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Windows
|
|
109
|
+
|
|
110
|
+
```powershell
|
|
111
|
+
# Check if uv is already installed
|
|
112
|
+
uv --version
|
|
113
|
+
|
|
114
|
+
# If not installed
|
|
115
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
β οΈ IMPORTANT: After installation, you must restart your terminal for the `uv` command to get picked up!
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
4. Add this flights MCP Server to your Claude for Desktop config:
|
|
122
|
+
|
|
123
|
+
#### MacOS
|
|
124
|
+
|
|
125
|
+
- Navigate to the config file location via Terminal: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
126
|
+
- OR if you have VSCode adn the Code alias, you can just create/edit using:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Windows
|
|
133
|
+
|
|
134
|
+
- Navigate to the config file location via PowerShell: `%AppData%\Claude\claude_desktop_config.json`
|
|
135
|
+
- OR if you have VSCode adn the Code alias, you can just create/edit using:
|
|
136
|
+
|
|
137
|
+
```powershell
|
|
138
|
+
code $env:AppData\Claude\claude_desktop_config.json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Note: `~/Library/Application Support/Claude/config.json` is a different, unrelated file. Do not edit it.
|
|
142
|
+
|
|
143
|
+
5. Add this flights MCP Server in the `mcpServers` key:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"mcpServers": {
|
|
148
|
+
"flights": {
|
|
149
|
+
"command": "/ABSOLUTE/PATH/.local/bin/uv",
|
|
150
|
+
"args": [
|
|
151
|
+
"--directory",
|
|
152
|
+
"/ABSOLUTE/PATH/TO/PARENT/FOLDER",
|
|
153
|
+
"run",
|
|
154
|
+
"flights.py"
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Make sure to modify the code to include the Absolute Path for `uv` for the `command` param and for the Absolute Path for the `args` param to this Repo.
|
|
162
|
+
|
|
163
|
+
You may need to put the full path to the `uv` executable in the command field. You can get this by running:
|
|
164
|
+
- `which uv` on MacOS/Linux
|
|
165
|
+
- `where uv` on Windows
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"flights": {
|
|
173
|
+
"command": "/Users/sahitmamidipaka/.local/bin/uv",
|
|
174
|
+
"args": [
|
|
175
|
+
"--directory",
|
|
176
|
+
"/Users/sahitmamidipaka/Documents/Google-Flights-MCP-Server",
|
|
177
|
+
"run",
|
|
178
|
+
"flights.py"
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
6. That's it! Open Claude for Desktop and you should see the little MCP Tools icon appear (make sure to re-open the app for updates to take placeβyou'll need to do this whenever you change your `claude_desktop_config.json` file π)
|
|
190
|
+
|
|
191
|
+
<!-- Claude Desktop MCP Tools Icon -->
|
|
192
|
+
<img src="./assets/images/claude-mcp-tool.png" alt="Claude Desktop MCP Tools Icon" />
|
|
193
|
+
|
|
194
|
+
For more information, refer to the [Official MCP Documentation](https://modelcontextprotocol.io/quickstart/server).
|
|
195
|
+
<br>
|
|
196
|
+
|
|
197
|
+
### Cursor
|
|
198
|
+
|
|
199
|
+
1. Open Cursor & Go to Settings
|
|
200
|
+
|
|
201
|
+
2. Press the MCP Tab on the Left Panel
|
|
202
|
+
|
|
203
|
+
3. Add a new MCP Server (Choose one):
|
|
204
|
+
|
|
205
|
+
#### Project Configuration
|
|
206
|
+
|
|
207
|
+
- Create a `.cursor/mcp.json` file in your project directory
|
|
208
|
+
- Ideal for tools specific to a single project
|
|
209
|
+
|
|
210
|
+
#### Global Configuration
|
|
211
|
+
|
|
212
|
+
- Create a `~/.cursor/mcp.json` file in your home directory
|
|
213
|
+
- Makes MCP servers available across all Cursor workspaces
|
|
214
|
+
|
|
215
|
+
4. Attach the following configuration in the `mcp.json` file:
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"mcpServers": {
|
|
220
|
+
"flights": {
|
|
221
|
+
"command": "uv",
|
|
222
|
+
"args": [
|
|
223
|
+
"--directory",
|
|
224
|
+
"/ABSOLUTE/PATH/TO/PARENT/FOLDER",
|
|
225
|
+
"run",
|
|
226
|
+
"flights.py"
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Make sure to replace `/ABSOLUTE/PATH/TO/PARENT/FOLDER` with the actual path to this repo.
|
|
234
|
+
|
|
235
|
+
You may need to put the full path to the `uv` executable in the command field. You can get this by running:
|
|
236
|
+
- `which uv` on MacOS/Linux
|
|
237
|
+
- `where uv` on Windows
|
|
238
|
+
|
|
239
|
+
Example:
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"mcpServers": {
|
|
244
|
+
"flights": {
|
|
245
|
+
"command": "/Users/sahitmamidipaka/.local/bin/uv",
|
|
246
|
+
"args": [
|
|
247
|
+
"--directory",
|
|
248
|
+
"/Users/sahitmamidipaka/Documents/Google-Flights-MCP-Server",
|
|
249
|
+
"run",
|
|
250
|
+
"flights.py"
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
<!-- Cursor MCP Image -->
|
|
259
|
+
<img src="./assets/images/cursor-mcp.png" alt="Cursor Flights MCP Image" />
|
|
260
|
+
|
|
261
|
+
For more information, refer to the [Official Cursor MCP Documentation](https://docs.cursor.com/context/model-context-protocol).
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
## π Example Usage
|
|
265
|
+
|
|
266
|
+
- Show me flight options from Atlanta to Shanghai for Jan 1 2026
|
|
267
|
+
- What are the prices like for flights from Detroit to Atlanta this weekend?
|
|
268
|
+
- I live in New York and want to go to Japan. Find the cheapest flight options leaving this Friday and consider all airports near me!
|
|
269
|
+
- Show me flight options for LAX today but only after 8:00 PM
|
|
270
|
+
|
|
271
|
+
## β¨ Upcoming Features
|
|
272
|
+
|
|
273
|
+
- Better Roundtrip Functionality π
|
|
274
|
+
- Multi-City Functionality π
|
|
275
|
+
- Explore / Go Anywhere Functionality πΊοΈ
|
|
276
|
+
- Price Graphs & Price History π
|
|
277
|
+
|
|
278
|
+
## π€ Contributing
|
|
279
|
+
|
|
280
|
+
Feel free to:
|
|
281
|
+
|
|
282
|
+
- Open issues for bugs or feature requests
|
|
283
|
+
- Submit pull requests
|
|
284
|
+
- Contact me directly at sahit.mamidipaka@gmail.com
|
|
285
|
+
|
|
286
|
+
## π License
|
|
287
|
+
|
|
288
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
289
|
+
|
|
290
|
+
This means you are free to:
|
|
291
|
+
|
|
292
|
+
- Use the software commercially
|
|
293
|
+
- Modify the source code
|
|
294
|
+
- Distribute the software
|
|
295
|
+
- Use the software privately
|
|
296
|
+
|
|
297
|
+
You must include the original copyright notice and citation in any distributed software or derivative works, as per the terms of the MIT License.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
Thank you for checking out this project! Always feel free to contact me for any reason.
|
|
302
|
+
|
|
303
|
+
> **Note:** This project was created for fun and is in no way endorsed or affiliated with Google, Google Flights, or any other Alphabet subsidiary company.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
flights.py,sha256=4wRRyyOGU65GXRLPrG2TOi4Te_PzAL741szt23hya1E,19975
|
|
2
|
+
iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/licenses/LICENSE,sha256=fiXVGGNZTFUCGa7ZDKwcTUGYB9AcZz5RteInw7Jsh6M,1073
|
|
3
|
+
iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/METADATA,sha256=UNgwie20eiEvNtpPJM34ZpogsUhaa2a8CMTD1AkzIwk,9262
|
|
4
|
+
iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
5
|
+
iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/entry_points.txt,sha256=n4cb6ZVRkSrtVdmRhkOBss1fM-Ur_i4p-38Sl7mxzeQ,45
|
|
6
|
+
iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/top_level.txt,sha256=4UhBDaKwrvR_ys9zGgF9IR8_poFFE5KcNh0oJHTHc-8,8
|
|
7
|
+
iflow_mcp_smamidipaka6_google_flights_mcp_server-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sahit Mamidipaka
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flights
|