11import asyncio
22import logging
3+ import tempfile
4+ from typing import Optional
35
46import mcp .types as types
57from mcp import StdioServerParameters
810from uipath import UiPath
911
1012from .._utils ._config import McpServer
11- from ._logger import NullLogger
1213from ._tracer import McpTracer
1314
1415logger = logging .getLogger (__name__ )
@@ -29,6 +30,11 @@ def __init__(self, server_config: McpServer, session_id: str):
2930 self ._message_queue = asyncio .Queue ()
3031 self ._uipath = UiPath ()
3132 self ._mcp_tracer = McpTracer (tracer , logger )
33+ self ._server_stderr_output : Optional [str ] = None
34+
35+ def get_server_stderr (self ) -> Optional [str ]:
36+ """Returns the captured stderr output from the MCP server process."""
37+ return self ._server_stderr_output
3238
3339 async def start (self ) -> None :
3440 """Start the server process in a separate task."""
@@ -59,44 +65,51 @@ async def start(self) -> None:
5965 async def _run_server (self , server_params : StdioServerParameters ) -> None :
6066 """Run the server in proper context managers."""
6167 logger .info (f"Starting server process for session { self .session_id } " )
62- try :
63- stderr_null = NullLogger ()
64-
65- async with stdio_client (server_params , errlog = stderr_null ) as (
66- read ,
67- write ,
68- ):
69- self .read_stream , self .write_stream = read , write
70- logger .info (f"Session { self .session_id } - stdio client started" )
68+ self . _server_stderr_output = None
69+ with tempfile . TemporaryFile ( mode = "w+" ) as stderr_temp :
70+ try :
71+ async with stdio_client (server_params , errlog = stderr_temp ) as (
72+ read ,
73+ write ,
74+ ):
75+ self .read_stream , self .write_stream = read , write
76+ logger .info (f"Session { self .session_id } - stdio client started" )
7177
72- # Start the message consumer task
73- consumer_task = asyncio .create_task (self ._consume_messages ())
78+ # Start the message consumer task
79+ consumer_task = asyncio .create_task (self ._consume_messages ())
7480
75- # Process incoming messages from the server
76- try :
77- while True :
78- logger .info ("Waiting for messages..." )
79- message = await self .read_stream .receive ()
80- await self .send_outgoing_message (message )
81- finally :
82- # Cancel the consumer when we exit the loop
83- consumer_task .cancel ()
81+ # Process incoming messages from the server
8482 try :
85- await consumer_task
86- except asyncio .CancelledError :
87- pass
83+ while True :
84+ logger .info (
85+ f"Session { self .session_id } : Waiting for messages..."
86+ )
87+ message = await self .read_stream .receive ()
88+ await self .send_outgoing_message (message )
89+ finally :
90+ stderr_temp .seek (0 )
91+ self ._server_stderr_output = stderr_temp .read ()
92+ logger .debug (
93+ f"Session { self .session_id } - Server stderr output:\n { self ._server_stderr_output } "
94+ )
95+ # Cancel the consumer when we exit the loop
96+ consumer_task .cancel ()
97+ try :
98+ await consumer_task
99+ except asyncio .CancelledError :
100+ pass
88101
89- except Exception as e :
90- logger .error (
91- f"Error in server process for session { self .session_id } : { e } " ,
92- exc_info = True ,
93- )
94- finally :
95- # The context managers will handle cleanup of resources
96- logger .info (f"Server process for session { self .session_id } has ended" )
97- self .read_stream = None
98- self .write_stream = None
99- self .mcp_session = None
102+ except Exception as e :
103+ logger .error (
104+ f"Error in server process for session { self .session_id } : { e } " ,
105+ exc_info = True ,
106+ )
107+ finally :
108+ # The context managers will handle cleanup of resources
109+ logger .info (f"Server process for session { self .session_id } has ended" )
110+ self .read_stream = None
111+ self .write_stream = None
112+ self .mcp_session = None
100113
101114 def _on_task_done (self , task ):
102115 """Handle task completion."""
0 commit comments