async def add_mcp_tool_(name: str, command: str, args: List[str], env: Dict[str, str]):
    """
    Add a tool from an MCP server.
    
    Args:
        name: Name prefix for the tools.
        command: Command to execute.
        args: Arguments for the command.
        env: Environment variables for the command.
    """
    def get_python_type(schema_type: str, format: Optional[str] = None) -> type:
        """Convert JSON schema type to Python type."""
        type_mapping = {
            "string": str,
            "integer": int,
            "boolean": bool,
            "number": float,
            "array": list,
            "object": dict,
        }
        return type_mapping.get(schema_type, Any)

    # Create a hashable key for the server instance
    env_items = frozenset(env.items()) if env else frozenset()
    server_key = (name, command, tuple(args), env_items)
    
    # Check if we already have a server instance with this configuration
    if server_key in _server_instances:
        server = _server_instances[server_key]
        logging.info(f"Reusing existing server instance for {name}")
    else:
        # Create a new server instance
        server = Server(command=command, args=args, env=env, name=name)
        _server_instances[server_key] = server
        if server.session is None:
                    await server.initialize()
        logging.info(f"Created new server instance for {name}")
    
    try:
        # Only initialize if the session is not already initialized
        
        tools_response = await server.list_tools()
        
        tools = tools_response.tools
        for tool in tools:
            tool_name: str = tool.name
            tool_desc: str = tool.description
            input_schema: Dict[str, Any] = tool.inputSchema
            properties: Dict[str, Dict[str, Any]] = input_schema.get("properties", {})
            required: List[str] = input_schema.get("required", [])

            def create_tool_function(
                tool_name: str,
                properties: Dict[str, Dict[str, Any]],
                required: List[str],
            ) -> Callable[..., Dict[str, Any]]:
                # Create function parameters type annotations
                annotations = {}
                defaults = {}

                # First add required parameters
                for param_name in required:
                    param_info = properties[param_name]
                    param_type = get_python_type(param_info.get("type", "any"))
                    annotations[param_name] = param_type

                # Then add optional parameters
                for param_name, param_info in properties.items():
                    if param_name not in required:
                        param_type = get_python_type(param_info.get("type", "any"))
                        annotations[param_name] = param_type
                        defaults[param_name] = param_info.get("default", None)

                # Create the signature parameters
                from inspect import Parameter, Signature
                
                parameters = []
                # Add required parameters first
                for param_name in required:
                    param_type = annotations[param_name]
                    parameters.append(
                        Parameter(
                            name=param_name,
                            kind=Parameter.POSITIONAL_OR_KEYWORD,
                            annotation=param_type
                        )
                    )
                
                # Add optional parameters
                for param_name, param_type in annotations.items():
                    if param_name not in required:
                        parameters.append(
                            Parameter(
                                name=param_name,
                                kind=Parameter.POSITIONAL_OR_KEYWORD,
                                annotation=param_type,
                                default=defaults[param_name]
                            )
                        )

                async def tool_function(*args: Any, **kwargs: Any) -> Dict[str, Any]:
                    # Convert positional args to kwargs
                    if len(args) > len(required):
                        raise TypeError(
                            f"{tool_name}() takes {len(required)} positional arguments but {len(args)} were given"
                        )

                    # Combine positional args with kwargs
                    all_kwargs = kwargs.copy()
                    for i, arg in enumerate(args):
                        if i < len(required):
                            all_kwargs[required[i]] = arg

                    # Validate required parameters
                    for req in required:
                        if req not in all_kwargs:
                            raise ValueError(f"Missing required parameter: {req}")

                    # Add defaults for optional parameters
                    for param, default in defaults.items():
                        if param not in all_kwargs:
                            all_kwargs[param] = default

                    # Get the server that was created at the higher level
                    env_items = frozenset(tool_function.env.items()) if tool_function.env else frozenset()

                    
                    try:
                            
                        # Remove None kwargs
                        all_kwargs = {k: v for k, v in all_kwargs.items() if v is not None}
                        result = await server.execute_tool(tool_name=tool_name, arguments=all_kwargs)
                        return {"result": result}
                    except Exception as e:
                        # Log the error but don't clean up the server as it's managed at the higher level
                        logging.error(f"Error executing tool {tool_name}: {str(e)}")
                        raise

                # Set function name and annotations
                tool_function.__name__ = tool_name
                tool_function.__annotations__ = {
                    **annotations,
                    "return": Dict[str, Any],
                }
                tool_function.__doc__ = f"{tool_desc}\n\nReturns:\n    Tool execution results"

                # Create and set the signature
                tool_function.__signature__ = Signature(
                    parameters=parameters,
                    return_annotation=Dict[str, Any]
                )

                # Store session parameters as attributes of the function
                tool_function.command = command
                tool_function.args = args
                tool_function.env = env

                return tool_function

            # Create function with proper annotations
            func = create_tool_function(tool_name, properties, required)
            # name should be name__function_name
            full_name = f"{name}__{tool_name}"
            func.__name__ = full_name

            add_tool_(func, description=tool_desc, properties=properties, required=required)
    except Exception as e:
        # Only clean up the server if there was an error
        logging.error(f"Error in add_mcp_tool_: {e}")
        await server.cleanup()
        raise
    # We don't clean up the server here to keep it alive for future use

    Add a tool from an MCP server.
    
    Args:
        name: Name prefix for the tools.
        command: Command to execute.
        args: Arguments for the command.
        env: Environment variables for the command.
    
src/upsonic/tools_server/server/tools.py