def tool(description: str = "", custom_properties: Dict[str, Any] = None, custom_required: List[str] = None):
    """
    Decorator to register a function as a tool.

    Args:
        description: Optional description of the tool. If not provided, function's docstring will be used.
    """

    def decorator(func: Callable):
        sig = inspect.signature(func)


        # Get parameter info
        properties = {}
        required = []

        # Extract description from docstring if not provided
        tool_description = description
        if not tool_description and func.__doc__:
            # Get the first line of the docstring as description
            tool_description = func.__doc__.strip().split('\n')[0].strip()


        
        for param_name, param in sig.parameters.items():
            param_type = (
                param.annotation if param.annotation != inspect.Parameter.empty else Any
            )
            param_default = (
                None if param.default == inspect.Parameter.empty else param.default
            )

            properties[param_name] = {
                "type": _get_json_type(param_type),
                "description": f"Parameter {param_name}",
            }

            if param_default is not None:
                properties[param_name]["default"] = param_default
            
            # If parameter has no default value, it's required
            if param.default == inspect.Parameter.empty:
                required.append(param_name)


        if custom_properties is not None:
            properties = custom_properties

        if custom_required is not None:
            required = custom_required

        # Register the function with the extracted description
        registered_functions[func.__name__] = {
            "function": func,
            "description": tool_description,
            "properties": properties,
            "required": required,
        }

        # Check if the function is async
        is_async = inspect.iscoroutinefunction(func)

        if is_async:
            @wraps(func)
            async def wrapper(*args, **kwargs):
                return await func(*args, **kwargs)
        else:
            @wraps(func)
            def wrapper(*args, **kwargs):
                return func(*args, **kwargs)

        return wrapper

    return decorator

    Decorator to register a function as a tool.

    Args:
        description: Optional description of the tool. If not provided, function's docstring will be used.
    
src/upsonic/tools_server/server/function_tools.py