LiamKhoaLe commited on
Commit
6c1b819
·
1 Parent(s): 3d6d107

Simplify MCP arch #2

Browse files
Files changed (2) hide show
  1. agent.py +5 -38
  2. app.py +33 -11
agent.py CHANGED
@@ -18,7 +18,6 @@ from pathlib import Path
18
  try:
19
  from mcp.server import Server
20
  from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource
21
- from mcp.server.models import InitializationOptions
22
  except ImportError:
23
  print("Error: MCP SDK not installed. Install with: pip install mcp", file=sys.stderr)
24
  sys.exit(1)
@@ -282,47 +281,15 @@ async def main():
282
 
283
  try:
284
  async with stdio_server() as streams:
285
- # Create initialization options
286
- # The Server class will automatically provide its capabilities based on
287
- # the registered @app.list_tools() and @app.call_tool() handlers
288
- try:
289
- # Try to get capabilities from the server if the method exists
290
- if hasattr(app, 'get_capabilities'):
291
- try:
292
- # Try with NotificationOptions if available
293
- from mcp.server.lowlevel.server import NotificationOptions
294
- server_capabilities = app.get_capabilities(
295
- notification_options=NotificationOptions(),
296
- experimental_capabilities={}
297
- )
298
- except (ImportError, AttributeError, TypeError):
299
- # Fallback: try without NotificationOptions
300
- try:
301
- server_capabilities = app.get_capabilities()
302
- except Exception:
303
- # If get_capabilities doesn't work, create minimal capabilities
304
- server_capabilities = {}
305
- else:
306
- # Server will provide capabilities automatically, use empty dict
307
- server_capabilities = {}
308
- except Exception:
309
- # Server will handle capabilities automatically
310
- server_capabilities = {}
311
-
312
- # Create initialization options
313
- init_options = InitializationOptions(
314
- server_name="gemini-mcp-server",
315
- server_version="1.0.0",
316
- capabilities=server_capabilities
317
- )
318
-
319
- # Run the server with initialization options
320
  logger.info("MCP server ready")
321
  try:
 
322
  await app.run(
323
  read_stream=streams[0],
324
- write_stream=streams[1],
325
- initialization_options=init_options
326
  )
327
  except Exception as run_error:
328
  logger.error(f"Error in app.run(): {run_error}")
 
18
  try:
19
  from mcp.server import Server
20
  from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource
 
21
  except ImportError:
22
  print("Error: MCP SDK not installed. Install with: pip install mcp", file=sys.stderr)
23
  sys.exit(1)
 
281
 
282
  try:
283
  async with stdio_server() as streams:
284
+ # The Server class automatically handles initialization and provides capabilities
285
+ # based on the registered @app.list_tools() and @app.call_tool() handlers
286
+ # No need to manually create InitializationOptions - the server handles this
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  logger.info("MCP server ready")
288
  try:
289
+ # Run the server - it will automatically handle the initialization handshake
290
  await app.run(
291
  read_stream=streams[0],
292
+ write_stream=streams[1]
 
293
  )
294
  except Exception as run_error:
295
  logger.error(f"Error in app.run(): {run_error}")
app.py CHANGED
@@ -264,9 +264,6 @@ async def get_mcp_session():
264
  stdio_ctx = stdio_client(server_params)
265
  read, write = await stdio_ctx.__aenter__()
266
 
267
- # Wait for the server process to start and be ready
268
- await asyncio.sleep(1.5) # Wait for server startup
269
-
270
  # Create ClientSession from the streams
271
  session = ClientSession(read, write)
272
 
@@ -278,12 +275,11 @@ async def get_mcp_session():
278
  # According to MCP protocol spec, the client MUST wait for the initialized notification
279
  # before sending any other requests (like list_tools)
280
  try:
 
 
 
281
  await session.__aenter__()
282
  logger.info("✅ MCP session initialized")
283
-
284
- # After __aenter__() completes, wait a bit longer to ensure server's internal state is ready
285
- # The server may have sent the initialized notification but needs time to set up handlers
286
- await asyncio.sleep(1.0) # Give server time to finalize internal state
287
  except Exception as e:
288
  error_msg = str(e)
289
  error_type = type(e).__name__
@@ -322,11 +318,24 @@ async def call_agent(user_prompt: str, system_prompt: str = None, files: list =
322
  return ""
323
 
324
  # List tools - session should be ready after proper initialization
 
 
325
  try:
326
  tools = await session.list_tools()
327
  except Exception as e:
328
- logger.error(f"❌ Failed to list MCP tools: {e}")
329
- return ""
 
 
 
 
 
 
 
 
 
 
 
330
 
331
  if not tools or not hasattr(tools, 'tools'):
332
  logger.error("Invalid tools response from MCP server")
@@ -694,11 +703,24 @@ async def search_web_mcp_tool(query: str, max_results: int = 5) -> list:
694
  return []
695
 
696
  # List tools - session should be ready after proper initialization
 
 
697
  try:
698
  tools = await session.list_tools()
699
  except Exception as e:
700
- logger.error(f"Failed to list MCP tools: {e}")
701
- return []
 
 
 
 
 
 
 
 
 
 
 
702
 
703
  if not tools or not hasattr(tools, 'tools'):
704
  return []
 
264
  stdio_ctx = stdio_client(server_params)
265
  read, write = await stdio_ctx.__aenter__()
266
 
 
 
 
267
  # Create ClientSession from the streams
268
  session = ClientSession(read, write)
269
 
 
275
  # According to MCP protocol spec, the client MUST wait for the initialized notification
276
  # before sending any other requests (like list_tools)
277
  try:
278
+ # The __aenter__() method properly handles the full initialization sequence
279
+ # including waiting for the server's initialized notification
280
+ # This is a blocking call that completes only after the server sends initialized
281
  await session.__aenter__()
282
  logger.info("✅ MCP session initialized")
 
 
 
 
283
  except Exception as e:
284
  error_msg = str(e)
285
  error_type = type(e).__name__
 
318
  return ""
319
 
320
  # List tools - session should be ready after proper initialization
321
+ # Add a small delay to ensure server has fully processed initialization
322
+ await asyncio.sleep(0.1)
323
  try:
324
  tools = await session.list_tools()
325
  except Exception as e:
326
+ error_msg = str(e)
327
+ # Check if it's an initialization error
328
+ if "initialization" in error_msg.lower() or "before initialization" in error_msg.lower():
329
+ logger.warning(f"⚠️ Server not ready yet, waiting a bit more...: {error_msg}")
330
+ await asyncio.sleep(0.5)
331
+ try:
332
+ tools = await session.list_tools()
333
+ except Exception as retry_error:
334
+ logger.error(f"❌ Failed to list MCP tools after retry: {retry_error}")
335
+ return ""
336
+ else:
337
+ logger.error(f"❌ Failed to list MCP tools: {error_msg}")
338
+ return ""
339
 
340
  if not tools or not hasattr(tools, 'tools'):
341
  logger.error("Invalid tools response from MCP server")
 
703
  return []
704
 
705
  # List tools - session should be ready after proper initialization
706
+ # Add a small delay to ensure server has fully processed initialization
707
+ await asyncio.sleep(0.1)
708
  try:
709
  tools = await session.list_tools()
710
  except Exception as e:
711
+ error_msg = str(e)
712
+ # Check if it's an initialization error
713
+ if "initialization" in error_msg.lower() or "before initialization" in error_msg.lower():
714
+ logger.warning(f"⚠️ Server not ready yet, waiting a bit more...: {error_msg}")
715
+ await asyncio.sleep(0.5)
716
+ try:
717
+ tools = await session.list_tools()
718
+ except Exception as retry_error:
719
+ logger.error(f"Failed to list MCP tools after retry: {retry_error}")
720
+ return []
721
+ else:
722
+ logger.error(f"Failed to list MCP tools: {error_msg}")
723
+ return []
724
 
725
  if not tools or not hasattr(tools, 'tools'):
726
  return []