@@ -58,7 +58,9 @@ def send_event(self, event_type: str, data):
5858 return False
5959
6060class _McpHttpRequestHandler (BaseHTTPRequestHandler ):
61- mcp_server : "McpServer"
61+ def __init__ (self , request , client_address , server ):
62+ self .mcp_server : "McpServer" = getattr (server , "mcp_server" )
63+ super ().__init__ (request , client_address , server )
6264
6365 def log_message (self , format , * args ):
6466 """Override to suppress default logging or customize"""
@@ -198,8 +200,8 @@ def __init__(self, name: str):
198200 self .name = name
199201 self .tools = McpToolRegistry ()
200202
201- self .http_server = None
202- self .server_thread = None
203+ self .http_server : ThreadingHTTPServer | None = None
204+ self .server_thread : threading . Thread | None = None
203205 self .running = False
204206 self .sse_connections : dict [str , _McpSseConnection ] = {}
205207
@@ -218,10 +220,44 @@ def serve(self, host: str, port: int):
218220 print ("[MCP] Server is already running" )
219221 return
220222
221- self .server_thread = threading .Thread (target = self ._run_server , daemon = True , args = (host , port ))
223+ # Create server with deferred binding
224+ self .http_server = ThreadingHTTPServer (
225+ (host , port ),
226+ _McpHttpRequestHandler ,
227+ bind_and_activate = False
228+ )
229+ self .http_server .allow_reuse_address = False
230+
231+ # Set the MCPServer instance on the handler class
232+ setattr (self .http_server , "mcp_server" , self )
233+
234+ try :
235+ # Bind and activate in main thread - errors propagate synchronously
236+ self .http_server .server_bind ()
237+ self .http_server .server_activate ()
238+ except OSError :
239+ # Cleanup on binding failure
240+ self .http_server .server_close ()
241+ self .http_server = None
242+ raise
243+
244+ # Only start thread after successful bind
222245 self .running = True
246+ def serve_forever ():
247+ try :
248+ self .http_server .serve_forever () # type: ignore
249+ except Exception as e :
250+ print (f"[MCP] Server error: { e } " )
251+ traceback .print_exc ()
252+ finally :
253+ self .running = False
254+ self .server_thread = threading .Thread (target = serve_forever , daemon = True )
223255 self .server_thread .start ()
224256
257+ print ("[MCP] Server started:" )
258+ print (f" Streamable HTTP: http://{ host } :{ port } /mcp" )
259+ print (f" SSE: http://{ host } :{ port } /sse" )
260+
225261 def stop (self ):
226262 if not self .running :
227263 return
@@ -260,32 +296,6 @@ def stdio(self, stdin: BinaryIO = sys.stdin.buffer, stdout: BinaryIO = sys.stdou
260296 except (BrokenPipeError , KeyboardInterrupt ): # Client disconnected
261297 break
262298
263- def _run_server (self , host : str , port : int ):
264- """Run the HTTP server main loop using ThreadingHTTPServer"""
265- # Set the MCPServer instance on the handler class
266- _McpHttpRequestHandler .mcp_server = self
267-
268-
269- # Create HTTP server with threading support and exclusive binding
270- self .http_server = ThreadingHTTPServer (
271- (host , port ),
272- _McpHttpRequestHandler
273- )
274- self .http_server .allow_reuse_address = False
275-
276- print ("[MCP] Server started:" )
277- print (f" Streamable HTTP: http://{ host } :{ port } /mcp" )
278- print (f" SSE: http://{ host } :{ port } /sse" )
279-
280- try :
281- # Serve until shutdown() is called
282- self .http_server .serve_forever ()
283- except Exception as e :
284- print (f"[MCP] Server error: { e } " )
285- traceback .print_exc ()
286- finally :
287- self .running = False
288-
289299 def _mcp_ping (self , _meta : dict | None = None ) -> dict :
290300 """MCP ping method"""
291301 return {}
0 commit comments