@@ -14,6 +14,17 @@ class MCPToolRunner(threading.Thread):
1414 """A dedicated thread for running MCP operations."""
1515
1616 def __init__ (self , server_params ):
17+ """
18+ Initializes the MCPToolRunner and starts its asynchronous processing thread.
19+
20+ Sets up queues for handling tool requests and results, configures an event to signal
21+ when initialization is complete, and stores the server parameters for establishing
22+ an MCP connection. The daemon thread is started immediately to manage asynchronous
23+ tool operations.
24+
25+ Args:
26+ server_params: Configuration parameters for connecting to the MCP server.
27+ """
1728 super ().__init__ (daemon = True )
1829 self .server_params = server_params
1930 self .queue = queue .Queue ()
@@ -23,11 +34,25 @@ def __init__(self, server_params):
2334 self .start ()
2435
2536 def run (self ):
26- """Main thread function that processes MCP requests."""
37+ """
38+ Starts the asynchronous loop to process MCP requests.
39+
40+ This method serves as the entry point for the dedicated thread,
41+ initializing an asyncio event loop to execute the internal
42+ asynchronous request processing routine.
43+ """
2744 asyncio .run (self ._run_async ())
2845
2946 async def _run_async (self ):
30- """Async entry point for MCP operations."""
47+ """
48+ Initializes the MCP session and processes tool requests asynchronously.
49+
50+ Establishes a connection with the MCP server using the provided parameters, initializes
51+ the session, and retrieves available tools before signaling readiness. Then, it enters
52+ a loop to poll an internal request queue for tool invocation requests, calling the
53+ appropriate tool for each request and enqueuing the result or error message. The loop
54+ exits gracefully when a shutdown signal or cancellation is encountered.
55+ """
3156 try :
3257 # Set up MCP session
3358 async with stdio_client (self .server_params ) as (read , write ):
@@ -69,7 +94,22 @@ async def _run_async(self):
6994 self .result_queue .put ((False , f"MCP initialization error: { str (e )} " ))
7095
7196 def call_tool (self , tool_name , arguments ):
72- """Call an MCP tool and wait for the result."""
97+ """
98+ Calls an MCP tool synchronously and returns its result.
99+
100+ This method waits for MCP initialization (up to 30 seconds) before proceeding. If initialization
101+ times out, it returns an error message. Otherwise, it enqueues the tool request with the specified
102+ arguments and waits for the result. If the tool execution fails, an error message is returned; if
103+ successful, the method extracts and returns the text content of the result when available, or a string
104+ representation of the result.
105+
106+ Parameters:
107+ tool_name: The name of the MCP tool to execute.
108+ arguments: The arguments to pass to the MCP tool.
109+
110+ Returns:
111+ A string containing the tool's output or an error message.
112+ """
73113 if not self .initialized .is_set ():
74114 self .initialized .wait (timeout = 30 )
75115 if not self .initialized .is_set ():
@@ -91,7 +131,12 @@ def call_tool(self, tool_name, arguments):
91131 return str (result )
92132
93133 def shutdown (self ):
94- """Signal the thread to shut down."""
134+ """
135+ Signals the worker thread to terminate.
136+
137+ Inserts a sentinel value (None) into the request queue, indicating that the thread should
138+ cease processing further requests.
139+ """
95140 self .queue .put (None )
96141
97142
@@ -130,15 +175,25 @@ class MCP:
130175
131176 def __init__ (self , command_or_string = None , args = None , * , command = None , ** kwargs ):
132177 """
133- Initialize the MCP connection and get tools.
178+ Initialize the MCP instance with command parsing and dynamic tool generation.
179+
180+ This method configures the MCP connection by interpreting command inputs. It accepts
181+ either a complete command stringβwhich is split into a command and its argumentsβor
182+ separate command and argument values. An alternative parameter name 'command' is also
183+ supported for backward compatibility. The method sets up the server parameters, starts
184+ the MCP tool runner, and waits up to 30 seconds for initialization, printing a warning
185+ if the process times out.
134186
135187 Args:
136- command_or_string: Either:
137- - The command to run the MCP server (e.g., Python path)
138- - A complete command string (e.g., "/path/to/python /path/to/app.py")
139- args: Arguments to pass to the command (when command_or_string is the command)
140- command: Alternative parameter name for backward compatibility
141- **kwargs: Additional parameters for StdioServerParameters
188+ command_or_string: A command executable or a complete command line to launch the
189+ MCP server. When provided as a string without separate arguments, it is split
190+ into the executable and its arguments.
191+ args: A list of arguments to pass to the command when it is provided separately.
192+ command: An alternative name for 'command_or_string' for backward compatibility.
193+ **kwargs: Additional keyword arguments passed to StdioServerParameters.
194+
195+ Raises:
196+ ValueError: If the provided command string is empty after parsing.
142197 """
143198 # Handle backward compatibility with named parameter 'command'
144199 if command_or_string is None and command is not None :
@@ -174,10 +229,14 @@ def __init__(self, command_or_string=None, args=None, *, command=None, **kwargs)
174229
175230 def _generate_tool_functions (self ) -> List [Callable ]:
176231 """
177- Generate functions for each MCP tool.
232+ Generates callable wrappers for each available MCP tool.
233+
234+ This method iterates over the tools provided by the MCP runner and creates a wrapper
235+ function for each using the _create_tool_wrapper method. The returned functions can be
236+ invoked directly to execute the corresponding MCP tool with the appropriate input schema.
178237
179238 Returns:
180- List[Callable]: Functions that can be used as tools
239+ List[Callable]: A list of callable wrappers for MCP tools.
181240 """
182241 tool_functions = []
183242
@@ -188,7 +247,25 @@ def _generate_tool_functions(self) -> List[Callable]:
188247 return tool_functions
189248
190249 def _create_tool_wrapper (self , tool ):
191- """Create a wrapper function for an MCP tool."""
250+ """
251+ Creates a dynamic wrapper for an MCP tool.
252+
253+ This function builds a callable that conforms to the tool's interface as defined
254+ by its input schema. It extracts parameter names, types, and required status from
255+ the tool's schema and constructs a wrapper with a matching signature and
256+ documentation. When invoked, the wrapper maps positional and keyword arguments
257+ to the expected parameters and calls the tool via the runner.
258+
259+ Parameters:
260+ tool: An MCP tool object with attributes 'name', 'description', and
261+ 'inputSchema'. The inputSchema should include a "properties" dictionary
262+ that defines parameter types and an optional "required" list for mandatory
263+ parameters.
264+
265+ Returns:
266+ A callable that wraps the tool, allowing it to be invoked with a signature
267+ that reflects its defined input parameters.
268+ """
192269 # Determine parameter names from the schema
193270 param_names = []
194271 param_annotations = {}
@@ -235,6 +312,11 @@ def _create_tool_wrapper(self, tool):
235312
236313 # Create function template to be properly decorated
237314 def template_function (* args , ** kwargs ):
315+ """
316+ Template function that accepts arbitrary arguments.
317+
318+ This placeholder function is intended for future extension and currently does not perform any operation; it always returns None.
319+ """
238320 return None
239321
240322 # Create a proper function with the correct signature
@@ -248,6 +330,20 @@ def template_function(*args, **kwargs):
248330 @wraps (template_function )
249331 def wrapper (* args , ** kwargs ):
250332 # Map positional args to parameter names
333+ """
334+ Invokes a tool using combined positional and keyword arguments.
335+
336+ This wrapper maps positional arguments to their corresponding expected
337+ parameter names, merges them with any keyword arguments, and delegates
338+ the call to the tool via the runner using the tool's name.
339+
340+ Args:
341+ *args: Positional values for the tool's parameters.
342+ **kwargs: Keyword arguments for the tool.
343+
344+ Returns:
345+ The result of executing the tool.
346+ """
251347 all_args = {}
252348 for i , arg in enumerate (args ):
253349 if i < len (param_names ):
@@ -273,6 +369,11 @@ def __iter__(self) -> Iterable[Callable]:
273369 return iter (self ._tools )
274370
275371 def __del__ (self ):
276- """Clean up resources when the object is garbage collected."""
372+ """
373+ Clean up resources when the MCP instance is garbage collected.
374+
375+ If the instance has an associated runner, its shutdown method is called to halt
376+ ongoing operations and release allocated resources.
377+ """
277378 if hasattr (self , 'runner' ):
278379 self .runner .shutdown ()
0 commit comments