Skip to main content
Glama

solve_ortools_problem

Solve constraint programming problems with Google OR-Tools by defining variables, constraints, and objectives. Returns solutions for problems like nurse scheduling, routing, or resource allocation.

Instructions

Solve a constraint programming problem using Google OR-Tools.

This tool takes a constraint programming problem defined with variables, constraints, and an optional objective, and returns a solution if one exists. Important Note: Each constraint expression must be a single evaluable Python statement. You cannot use Python control flow (loops, if statements) in the expressions. Instead, you need to generate separate constraints for each case. Example: Nurse Scheduling Problem: ```python # Schedule 4 nurses across 3 shifts over 3 days shifts_var = Variable( name="shifts_var", type=VariableType.BOOLEAN, shape=[4, 3, 3], # [nurses, days, shifts] description="Binary variable indicating if a nurse works a shift", ) constraints = [] # INCORRECT - This will fail: # Constraint( # expression=( # "for d in range(3): for s in range(3): " # "model.add(sum([shifts_var[n][d][s] for n in range(4)]) == 1)" # ) # ) # CORRECT - Add each constraint separately: # Each shift must have exactly one nurse for d in range(3): for s in range(3): constraints.append( Constraint( expression=f"model.add(sum([shifts_var[n][{d}][{s}] for n in range(4)]) == 1)", description=f"One nurse for day {d}, shift {s}", ) ) # Each nurse works at most one shift per day for n in range(4): for d in range(3): constraints.append( Constraint( expression=f"model.add(sum([shifts_var[{n}][{d}][s] for s in range(3)]) <= 1)", description=f"Max one shift for nurse {n} on day {d}", ) ) # Each nurse works 2-3 shifts total for n in range(4): constraints.append( Constraint( expression=f"model.add(sum([shifts_var[{n}][d][s] for d in range(3) for s in range(3)]) >= 2)", description=f"Min shifts for nurse {n}", ) ) problem = Problem( variables=[shifts_var], constraints=constraints, description="Hospital nurse scheduling problem", ) ``` Args: problem: The problem definition with variables, constraints, and optional objective Returns: A list of TextContent containing the solution or an error message

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
problemYes

Implementation Reference

  • The FastMCP tool handler for 'solve_ortools_problem'. It receives an ORToolsProblem, invokes the OR-Tools solver via solve_ortools_problem, and formats the result as TextContent list.
    @app.tool("solve_ortools_problem") async def solve_ortools_problem_tool( problem: ORToolsProblem, ) -> list[TextContent]: """Solve a constraint programming problem using Google OR-Tools. This tool takes a constraint programming problem defined with variables, constraints, and an optional objective, and returns a solution if one exists. Important Note: Each constraint expression must be a single evaluable Python statement. You cannot use Python control flow (loops, if statements) in the expressions. Instead, you need to generate separate constraints for each case. Example: Nurse Scheduling Problem: ```python # Schedule 4 nurses across 3 shifts over 3 days shifts_var = Variable( name="shifts_var", type=VariableType.BOOLEAN, shape=[4, 3, 3], # [nurses, days, shifts] description="Binary variable indicating if a nurse works a shift", ) constraints = [] # INCORRECT - This will fail: # Constraint( # expression=( # "for d in range(3): for s in range(3): " # "model.add(sum([shifts_var[n][d][s] for n in range(4)]) == 1)" # ) # ) # CORRECT - Add each constraint separately: # Each shift must have exactly one nurse for d in range(3): for s in range(3): constraints.append( Constraint( expression=f"model.add(sum([shifts_var[n][{d}][{s}] for n in range(4)]) == 1)", description=f"One nurse for day {d}, shift {s}", ) ) # Each nurse works at most one shift per day for n in range(4): for d in range(3): constraints.append( Constraint( expression=f"model.add(sum([shifts_var[{n}][{d}][s] for s in range(3)]) <= 1)", description=f"Max one shift for nurse {n} on day {d}", ) ) # Each nurse works 2-3 shifts total for n in range(4): constraints.append( Constraint( expression=f"model.add(sum([shifts_var[{n}][d][s] for d in range(3) for s in range(3)]) >= 2)", description=f"Min shifts for nurse {n}", ) ) problem = Problem( variables=[shifts_var], constraints=constraints, description="Hospital nurse scheduling problem", ) ``` Args: problem: The problem definition with variables, constraints, and optional objective Returns: A list of TextContent containing the solution or an error message """ result = solve_ortools_problem(problem) match result: case Success(solution): return [ TextContent( type="text", text=json.dumps( { "values": solution.values, "is_feasible": solution.is_feasible, "status": solution.status, "objective_value": solution.objective_value, "statistics": solution.statistics, } ), ) ] case Failure(error): return [TextContent(type="text", text=f"Error solving problem: {error}")] case _: return [ TextContent( type="text", text="Unexpected error in solve_ortools_problem_tool", ) ]
  • Pydantic BaseModel defining the input schema ORToolsProblem (imported as Problem). Includes variables, constraints, optional objective and parameters.
    class Problem(BaseModel): """Model representing a complete OR-Tools constraint programming problem.""" variables: list[Variable] constraints: list[Constraint] objective: Objective | None = None parameters: dict[str, Any] = Field(default_factory=dict) description: str = ""
  • FastMCP decorator registering the solve_ortools_problem_tool as an MCP tool.
    @app.tool("solve_ortools_problem")
  • Main solver function (exported as solve_ortools_problem) that constructs CpModel from problem spec, adds vars/constraints/objective, solves with CpSolver, extracts solution values and stats.
    def solve_problem(problem: Problem) -> Result[Solution, str]: """Solve an OR-Tools problem and return the solution. Args: problem: The problem definition Returns: Result containing a Solution or an error message """ try: # Create model model = cp_model.CpModel() # Create variables vars_result = create_variables(model, problem.variables) if isinstance(vars_result, Failure): return vars_result variables_dict, globals_dict = vars_result.unwrap() # Create constraints constraints_result = create_constraints( model, problem.constraints, variables_dict, globals_dict ) if isinstance(constraints_result, Failure): return constraints_result # Add objective objective_result = add_objective( model, problem.objective, variables_dict, globals_dict ) if isinstance(objective_result, Failure): return objective_result # Create solver solver = cp_model.CpSolver() # Add parameters if provided if problem.parameters: for key, value in problem.parameters.items(): if hasattr(solver.parameters, key): setattr(solver.parameters, key, value) # Solve the problem status = solver.Solve(model) # Extract solution is_feasible = status in [ cp_model.OPTIMAL, cp_model.FEASIBLE, ] values = ( extract_solution(solver, variables_dict, problem.variables) if is_feasible else {} ) return Success( Solution( values=values, is_feasible=is_feasible, status=solver.StatusName(status), objective_value=( solver.ObjectiveValue() if is_feasible and problem.objective else None ), statistics={ "num_conflicts": solver.NumConflicts(), "num_branches": solver.NumBranches(), "wall_time": solver.WallTime(), }, ) ) except Exception as e: return Failure(f"Error solving problem: {e!s}")
  • Pydantic model for the solver output Solution.
    class Solution(BaseModel): """Model representing a solution to an OR-Tools problem.""" values: dict[str, Any] is_feasible: bool status: str objective_value: float | None = None statistics: dict[str, Any] = Field(default_factory=dict)

Other Tools

Related Tools

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/sdiehl/usolver'

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