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