-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmcp_server.py
More file actions
135 lines (120 loc) · 4.43 KB
/
Copy pathmcp_server.py
File metadata and controls
135 lines (120 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import sys
import json
import logging
from fast_flights import FlightData, Passengers, get_flights
# Configure logging to file since stdout is used for protocol
logging.basicConfig(filename='mcp_server.log', level=logging.INFO)
def search_logic(origin, dest, date):
logging.info(f"Searching: {origin} -> {dest} on {date}")
try:
result = get_flights(
flight_data=[FlightData(date=date, from_airport=origin, to_airport=dest)],
trip="one-way",
seat="economy",
passengers=Passengers(adults=1, children=0, infants_in_seat=0, infants_on_lap=0),
fetch_mode="fallback"
)
flights = []
for f in result.flights[:10]: # Limit to top 10
flights.append({
"name": f.name,
"price": f.price,
"duration": f.duration,
"departure": f.departure,
"arrival": f.arrival,
"stops": f.stops
})
return {
"current_price": result.current_price,
"flights": flights
}
except Exception as e:
logging.error(f"Search failed: {e}")
raise e
def handle_request(req):
method = req.get("method")
msg_id = req.get("id")
if method == "initialize":
return {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": { "tools": {} },
"serverInfo": { "name": "flights-skill", "version": "1.0.0" }
}
}
if method == "notifications/initialized":
# Client confirming initialization. No response needed.
return None
if method == "tools/list":
return {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"tools": [{
"name": "search_flights",
"description": "Search for one-way flights using Google Flights data (Real-time pricing).",
"inputSchema": {
"type": "object",
"properties": {
"origin": { "type": "string", "description": "Origin Airport Code (e.g. SFO)" },
"destination": { "type": "string", "description": "Destination Airport Code (e.g. JFK)" },
"date": { "type": "string", "description": "Date in YYYY-MM-DD format" }
},
"required": ["origin", "destination", "date"]
}
}]
}
}
if method == "tools/call":
params = req.get("params", {})
if params.get("name") == "search_flights":
args = params.get("arguments", {})
try:
data = search_logic(args.get("origin"), args.get("destination"), args.get("date"))
return {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"content": [{ "type": "text", "text": json.dumps(data, indent=2) }]
}
}
except Exception as e:
return {
"jsonrpc": "2.0",
"id": msg_id,
"error": { "code": -32000, "message": str(e) }
}
else:
return {
"jsonrpc": "2.0",
"id": msg_id,
"error": { "code": -32601, "message": "Method not found" }
}
# Default for unknown methods (ping etc)
# MCP requires ignoring notifications, but replying error to requests
if msg_id is not None:
return {
"jsonrpc": "2.0",
"id": msg_id,
"error": { "code": -32601, "message": "Method not found or not implemented" }
}
return None
def main():
while True:
try:
line = sys.stdin.readline()
if not line: break
try:
req = json.loads(line)
except json.JSONDecodeError:
continue
res = handle_request(req)
if res:
print(json.dumps(res))
sys.stdout.flush()
except Exception as e:
logging.critical(f"Critical Loop Error: {e}")
if __name__ == "__main__":
main()