Skip to main content
Glama
Sharmarajnish

Constrained Optimization MCP Server

solve_convex_optimization

Solve convex optimization problems with CVXPY by defining variables, objectives, and constraints for linear, quadratic, and semidefinite programming.

Instructions

Solve convex optimization problems using CVXPY.

This tool is ideal for mathematical optimization problems with convex objectives
and constraints, including linear programming, quadratic programming, and
semidefinite programming.

Args:
    variables: List of variable definitions with 'name' and 'shape'
    objective_type: Either 'minimize' or 'maximize'
    objective_expr: The objective function expression as a string
    constraints: List of constraint expressions as strings
    parameters: Dictionary of parameter values (e.g., matrices A, b)
    description: Optional problem description
    
Returns:
    Solution results including variable values and objective value
    
Example:
    variables = [{"name": "x", "shape": 2}]
    objective_type = "minimize"
    objective_expr = "cp.sum_squares(x)"
    constraints = ["x >= 0", "cp.sum(x) == 1"]

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
constraintsYes
descriptionNo
objective_exprYes
objective_typeYes
parametersNo
variablesYes

Implementation Reference

  • The primary handler function for the 'solve_convex_optimization' tool. It processes input arguments, constructs a CVXPYProblem instance, calls the solve_cvxpy_problem helper, handles Success/Failure results, serializes to JSON, and returns TextContent responses or error messages.
    @app.tool("solve_convex_optimization")
    async def solve_convex_optimization(
        variables: List[dict[str, Any]],
        objective_type: str,
        objective_expr: str,
        constraints: List[str],
        parameters: dict[str, Any] = None,
        description: str = "",
    ) -> List[TextContent]:
        """
        Solve convex optimization problems using CVXPY.
        
        This tool is ideal for mathematical optimization problems with convex objectives
        and constraints, including linear programming, quadratic programming, and
        semidefinite programming.
        
        Args:
            variables: List of variable definitions with 'name' and 'shape'
            objective_type: Either 'minimize' or 'maximize'
            objective_expr: The objective function expression as a string
            constraints: List of constraint expressions as strings
            parameters: Dictionary of parameter values (e.g., matrices A, b)
            description: Optional problem description
            
        Returns:
            Solution results including variable values and objective value
            
        Example:
            variables = [{"name": "x", "shape": 2}]
            objective_type = "minimize"
            objective_expr = "cp.sum_squares(x)"
            constraints = ["x >= 0", "cp.sum(x) == 1"]
        """
        try:
            # Convert to CVXPY problem
            problem_variables = []
            for var in variables:
                if "name" not in var or "shape" not in var:
                    return [
                        TextContent(
                            type="text",
                            text="Each variable must have 'name' and 'shape' fields",
                        )
                    ]
    
                problem_variables.append(CVXPYVariable(**var))
    
            try:
                from ..models.cvxpy_models import ObjectiveType
                obj_type = ObjectiveType(objective_type)
            except ValueError:
                return [
                    TextContent(
                        type="text",
                        text=(
                            f"Invalid objective type: {objective_type}. "
                            f"Must be one of: minimize, maximize"
                        ),
                    )
                ]
    
            from ..models.cvxpy_models import CVXPYObjective, CVXPYConstraint
            objective = CVXPYObjective(type=obj_type, expression=objective_expr)
            problem_constraints = [CVXPYConstraint(expression=expr) for expr in constraints]
    
            problem = CVXPYProblem(
                variables=problem_variables,
                objective=objective,
                constraints=problem_constraints,
                parameters=parameters or {},
                description=description,
            )
    
            # Solve the problem
            result = solve_cvxpy_problem(problem)
    
            match result:
                case Success(solution):
                    return [
                        TextContent(
                            type="text",
                            text=json.dumps(
                                {
                                    "values": {
                                        k: v.tolist() if hasattr(v, "tolist") else v
                                        for k, v in solution.values.items()
                                    },
                                    "objective_value": solution.objective_value,
                                    "status": solution.status,
                                    "solve_time": solution.solve_time,
                                    "dual_values": {
                                        k: v.tolist() if hasattr(v, "tolist") else v
                                        for k, v in (solution.dual_values or {}).items()
                                    },
                                }
                            ),
                        )
                    ]
                case Failure(error):
                    return [TextContent(type="text", text=f"Error solving problem: {error}")]
        except Exception as e:
            return [TextContent(type="text", text=f"Error in solve_convex_optimization: {e!s}")]
  • FastMCP tool registration decorator that registers solve_convex_optimization as a callable tool.
    @app.tool("solve_convex_optimization")
  • Core implementation that constructs the actual CVXPY optimization problem from the CVXPYProblem model, parses string expressions into CVXPY objects using safe eval, solves the problem, extracts primal/dual values, status, timings, and returns a structured CVXPYSolution.
    def solve_cvxpy_problem(problem: CVXPYProblem) -> Result[CVXPYSolution, str]:
        """Solve a CVXPY optimization problem.
    
        Args:
            problem: The problem definition
    
        Returns:
            Result containing a CVXPYSolution or an error message
        """
        try:
            # Validate problem
            if not problem.validate():
                return Failure("Invalid problem definition")
    
            start_time = time.time()
            
            # Create variables
            variables: Dict[str, cp.Variable] = {}
            for var in problem.variables:
                variables[var.name] = create_variable(var)
    
            # Parse objective
            objective_expr = parse_expression(
                problem.objective.expression, variables, problem.parameters
            )
            objective = (
                cp.Minimize(objective_expr)
                if problem.objective.type == ObjectiveType.MINIMIZE
                else cp.Maximize(objective_expr)
            )
    
            # Parse constraints
            constraints = []
            for constraint in problem.constraints:
                constraint_expr = parse_expression(
                    constraint.expression, variables, problem.parameters
                )
                constraints.append(constraint_expr)
    
            # Create and solve the problem
            prob = cp.Problem(objective, constraints)
            
            # Set solver options if specified
            solver_kwargs = {}
            if problem.solver:
                solver_kwargs["solver"] = problem.solver
            if problem.max_iters:
                solver_kwargs["max_iters"] = problem.max_iters
                
            result = prob.solve(verbose=problem.verbose, **solver_kwargs)
            solve_time = time.time() - start_time
    
            # Extract solution
            values = {name: var.value for name, var in variables.items()}
            dual_values = {
                i: constraint.dual_value
                for i, constraint in enumerate(constraints)
                if hasattr(constraint, "dual_value") and constraint.dual_value is not None
            }
    
            # Get solver statistics
            solver_stats = {}
            if hasattr(prob, "solver_stats"):
                solver_stats = prob.solver_stats
    
            return Success(
                CVXPYSolution(
                    values=values,
                    objective_value=float(result) if result is not None else None,
                    status=prob.status,
                    dual_values=dual_values if dual_values else None,
                    solve_time=solve_time,
                    solver_stats=solver_stats,
                    problem_value=prob.value,
                )
            )
        except Exception as e:
            return Failure(f"Error solving CVXPY problem: {e!s}")
  • Pydantic model defining the input schema for CVXPY problems, including variables, objective, constraints, parameters, and solver options. Used for validation and serialization in the handler.
    class CVXPYProblem(BaseProblem):
        """Model representing a complete CVXPY optimization problem."""
    
        variables: List[CVXPYVariable] = Field(..., description="Problem variables")
        objective: CVXPYObjective = Field(..., description="Problem objective")
        constraints: List[CVXPYConstraint] = Field(..., description="Problem constraints")
        parameters: Dict[str, Any] = Field(default_factory=dict, description="Problem parameters")
        description: str = Field(default="", description="Problem description")
        
        # CVXPY-specific properties
        problem_type: ProblemType = Field(default=ProblemType.CONVEX_OPTIMIZATION, description="Problem type")
        sense: OptimizationSense = Field(..., description="Optimization sense")
        
        # Solver options
        solver: Optional[str] = Field(default=None, description="Preferred solver")
        verbose: bool = Field(default=False, description="Verbose output")
        max_iters: Optional[int] = Field(default=None, description="Maximum iterations")
    
        def get_variables(self) -> List[BaseVariable]:
            """Get all variables in the problem."""
            return self.variables
    
        def get_constraints(self) -> List[BaseConstraint]:
            """Get all constraints in the problem."""
            return self.constraints
    
        def validate(self) -> bool:
            """Validate the problem definition."""
            if not self.variables:
                return False
            if not self.objective:
                return False
            
            # Check that all variable names are unique
            var_names = [var.name for var in self.variables]
            if len(var_names) != len(set(var_names)):
                return False
                
            return True
  • Enum and model for objective definition used in CVXPYProblem.
    class ObjectiveType(str, Enum):
        """Enum for objective types in CVXPY."""
    
        MINIMIZE = "minimize"
        MAXIMIZE = "maximize"
    
    
    class CVXPYVariable(BaseVariable):
        """Model representing a CVXPY variable."""
    
        name: str = Field(..., description="Variable name")
        shape: Union[int, tuple[int, ...]] = Field(..., description="Variable shape (scalar or array)")
        description: str = Field(default="", description="Variable description")
        
        # CVXPY-specific properties
        var_type: VariableType = Field(default=VariableType.REAL, description="Variable type")
        nonneg: bool = Field(default=False, description="Non-negative constraint")
        nonpos: bool = Field(default=False, description="Non-positive constraint")
        symmetric: bool = Field(default=False, description="Symmetric matrix constraint")
        diag: bool = Field(default=False, description="Diagonal matrix constraint")
        hermitian: bool = Field(default=False, description="Hermitian matrix constraint")
        complex: bool = Field(default=False, description="Complex variable")
        
        # Bounds
        lower_bound: Optional[float] = Field(default=None, description="Lower bound")
        upper_bound: Optional[float] = Field(default=None, description="Upper bound")
    
        def get_bounds(self) -> tuple[Optional[float], Optional[float]]:
            """Get variable bounds (lower, upper)."""
            return self.lower_bound, self.upper_bound
    
    
    class CVXPYConstraint(BaseConstraint):
        """Model representing a CVXPY constraint."""
    
        expression: str = Field(..., description="Constraint expression as string")
        description: str = Field(default="", description="Constraint description")
        
        # CVXPY-specific properties
        constraint_type: ConstraintType = Field(default=ConstraintType.LINEAR_INEQUALITY, description="Type of constraint")
        is_equality: bool = Field(default=False, description="Whether constraint is equality")
        is_inequality: bool = Field(default=True, description="Whether constraint is inequality")
    
        def is_linear(self) -> bool:
            """Check if constraint is linear."""
            # Simple heuristic - CVXPY constraints are typically linear
            # unless they involve non-linear functions
            non_linear_indicators = ["**", "^", "sqrt", "log", "exp", "sin", "cos", "quad_form", "norm"]
            expr_lower = self.expression.lower()
            return not any(indicator in expr_lower for indicator in non_linear_indicators)
    
    
    class CVXPYObjective(BaseModel):
        """Model representing a CVXPY objective."""
    
        type: ObjectiveType = Field(..., description="Objective type")
        expression: str = Field(..., description="Objective function expression as string")
        description: str = Field(default="", description="Objective description")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sharmarajnish/MCP-Constrained-Optimization'

If you have feedback or need assistance with the MCP directory API, please join our Discord server