carban/minizinc-mcp

MCP server that exposes MiniZinc constraint solving and optimization to LLM clients like opencode, Claude Desktop, and Cursor

0

stars

15

commits

Python

primary language

Sep 15, 2026

updated

constrained-optimization
constraint-programming
constraint-satisfaction-problem
constraint-solver
mcp
mcp-server
mcp-tools
minizinc
python

README

MiniZinc MCP Server

MiniZinc MCP Server logo

An MCP server that exposes MiniZinc constraint solving and optimization to LLM clients such as opencode, Claude Desktop, and Cursor. It lets an agent parse, type-check, and solve MiniZinc models directly from a chat session.

Built with the MCP Python SDK v2 and the MiniZinc Python binding.


Demo

MiniZinc MCP Server Demo

Install it

1. Prerequisites

Only two things need to be installed, once per machine:

  • uvcurl -LsSf https://astral.sh/uv/install.sh | sh
  • MiniZinc 2.6+ with the minizinc executable on PATH (includes a default solver, Gecode)

Everything else is fetched automatically by uv — there is no clone, no venv setup, and no manual pip install on your side.

2. Install the server (pick one)

Install it globally (best if you use it in several projects):

uv tool install --from git+https://github.com/carban/minizinc-mcp minizinc-mcp

Or run it on demand each time, with nothing installed:

uvx --from git+https://github.com/carban/minizinc-mcp minizinc-mcp

3. Wire it into your MCP client

The server runs over stdio. Tell your MCP client to launch it:

opencode — project level (add this to opencode.jsonc in your project):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "minizinc": {
      "type": "local",
      "command": ["uvx", "--from", "git+https://github.com/carban/minizinc-mcp", "minizinc-mcp"]
    }
  }
}

opencode — global (add the same mcp.minizinc block to ~/.config/opencode/opencode.json):

{
  "mcp": {
    "minizinc": {
      "type": "local",
      "command": ["uvx", "--from", "git+https://github.com/carban/minizinc-mcp", "minizinc-mcp"]
    }
  }
}

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "minizinc": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/carban/minizinc-mcp", "minizinc-mcp"]
    }
  }
}

4. Verify it works

Restart your client. Six tools should now be available, prefixed with minizinc_:

  • minizinc_list_solvers
  • minizinc_validate_model
  • minizinc_solve_model
  • minizinc_solve_model_by_path
  • minizinc_get_model_info
  • minizinc_get_flatzinc

Quick sanity check — ask your client: "list the available MiniZinc solvers". You should see gecode, chuffed, highs, and anything else installed on the machine.


What it does

ToolDescription
list_solversLists every MiniZinc solver installed on the machine. The returned tag names (e.g. gecode, chuffed, highs) can be passed to solve_model.
validate_modelParses and type-checks MiniZinc model code without solving it. Useful for checking model syntax up front. Returns VALID or INVALID with an error message.
solve_modelSolves a MiniZinc model given as source code: once, exhaustively (all_solutions), or with a solution / time limit. Returns the status, solution(s), objective value (for optimization problems), and solver statistics.
solve_model_by_pathSame as solve_model but loads the model and its optional data (.dzn) file from paths instead of source code.
get_model_infoInspects a model without solving it: returns its solve method (satisfy/minimize/maximize) and the declared input parameters and output variables with their types. Useful for an agent to know exactly which params a model expects.
get_flatzincCompiles a model (and optional data) to FlatZinc text without solving it. Returns the .fzn model, the .ozn output model, and flattening statistics. Useful for debugging and low-level inspection.

solve_model arguments

ArgumentTypeDefaultDescription
model_codestr(required)The MiniZinc source code (.mzn) of the model.
paramsdict | strNoneParameter assignments like a .dzn file: a JSON object mapping names to values (a JSON string encoding such an object is also accepted).
solverstr"gecode"Which solver to use (see list_solvers).
all_solutionsboolFalseCompute all solutions of a solve satisfy problem.
max_solutionsint | NoneNoneStop after at most this many solutions.
timeout_secondsint | NoneNoneSolver time limit in seconds.

The result is a JSON object like:

{
  "status": "OPTIMAL_SOLUTION",
  "objective": 9,
  "solution": { "objective": 9, "x": 9, "y": 1 },
  "statistics": { "time": 0.204, "nodes": 3, ... }
}

status is one of SATISFIED, OPTIMAL_SOLUTION, ALL_SOLUTIONS, UNSATISFIABLE, UNKNOWN, or ERROR. validate_model and solve_model never raise in normal operation — errors are returned inside the result dict.


Developing locally

Clone the repo, then:

uv sync          # create the environment and install mcp + minizinc

The server speaks the MCP stdio transport, so it is launched as a subprocess by an MCP client. Run it with the SDK inspector:

uv run mcp dev server.py

that opens the MCP Inspector in the browser where every tool can be called interactively. A minimal programmatic smoke test:

uv run python -c "
import asyncio
from mcp import Client
from mcp.client.stdio import StdioServerParameters

async def main():
    params = StdioServerParameters(command='uv', args=['run', 'python', 'server.py'], cwd='.')
    async with Client(params) as client:
        result = await client.call_tool('solve_model', {
            'model_code': 'var 1..10: x; var 1..10: y; constraint x + y = 10; solve maximize x;'
        })
        print(result.content[0].text)

asyncio.run(main())
"

Running the tests

Install the test dependencies, then run the suite:

uv sync --group dev
uv run pytest -q

The tests in tests/ launch the server end-to-end over stdio and call every tool through the MCP protocol, solving the example model in example/. They need a working MiniZinc install (the same prerequisite as for developers).

Notes and limitations

  • params follows JSON representation: JSON arrays map to MiniZinc arrays; numbers, strings, and booleans map to their native MiniZinc types. Exotic types like sets and enums are not fully expressible this way.
  • Do not combine all_solutions with max_solutions; the MiniZinc driver rejects the combination.
  • MiniZinc requires a solver that supports the model (e.g. chuffed/gecode for CP, highs/cbc for MIP models). Use list_solvers to see what is installed.
  • Solutions are returned inline in the tool result; read_only_hint is set on all tools, so they do not modify your files or system.

Contributors

carban

15 commits

carban/minizinc-mcp

MCP server that exposes MiniZinc constraint solving and optimization to LLM clients like opencode, Claude Desktop, and Cursor

0

stars

15

commits

Python

primary language

Sep 15, 2026

updated

constrained-optimization
constraint-programming
constraint-satisfaction-problem
constraint-solver
mcp
mcp-server
mcp-tools
minizinc
python

README

MiniZinc MCP Server

MiniZinc MCP Server logo

An MCP server that exposes MiniZinc constraint solving and optimization to LLM clients such as opencode, Claude Desktop, and Cursor. It lets an agent parse, type-check, and solve MiniZinc models directly from a chat session.

Built with the MCP Python SDK v2 and the MiniZinc Python binding.


Demo

MiniZinc MCP Server Demo

Install it

1. Prerequisites

Only two things need to be installed, once per machine:

  • uvcurl -LsSf https://astral.sh/uv/install.sh | sh
  • MiniZinc 2.6+ with the minizinc executable on PATH (includes a default solver, Gecode)

Everything else is fetched automatically by uv — there is no clone, no venv setup, and no manual pip install on your side.

2. Install the server (pick one)

Install it globally (best if you use it in several projects):

uv tool install --from git+https://github.com/carban/minizinc-mcp minizinc-mcp

Or run it on demand each time, with nothing installed:

uvx --from git+https://github.com/carban/minizinc-mcp minizinc-mcp

3. Wire it into your MCP client

The server runs over stdio. Tell your MCP client to launch it:

opencode — project level (add this to opencode.jsonc in your project):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "minizinc": {
      "type": "local",
      "command": ["uvx", "--from", "git+https://github.com/carban/minizinc-mcp", "minizinc-mcp"]
    }
  }
}

opencode — global (add the same mcp.minizinc block to ~/.config/opencode/opencode.json):

{
  "mcp": {
    "minizinc": {
      "type": "local",
      "command": ["uvx", "--from", "git+https://github.com/carban/minizinc-mcp", "minizinc-mcp"]
    }
  }
}

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "minizinc": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/carban/minizinc-mcp", "minizinc-mcp"]
    }
  }
}

4. Verify it works

Restart your client. Six tools should now be available, prefixed with minizinc_:

  • minizinc_list_solvers
  • minizinc_validate_model
  • minizinc_solve_model
  • minizinc_solve_model_by_path
  • minizinc_get_model_info
  • minizinc_get_flatzinc

Quick sanity check — ask your client: "list the available MiniZinc solvers". You should see gecode, chuffed, highs, and anything else installed on the machine.


What it does

ToolDescription
list_solversLists every MiniZinc solver installed on the machine. The returned tag names (e.g. gecode, chuffed, highs) can be passed to solve_model.
validate_modelParses and type-checks MiniZinc model code without solving it. Useful for checking model syntax up front. Returns VALID or INVALID with an error message.
solve_modelSolves a MiniZinc model given as source code: once, exhaustively (all_solutions), or with a solution / time limit. Returns the status, solution(s), objective value (for optimization problems), and solver statistics.
solve_model_by_pathSame as solve_model but loads the model and its optional data (.dzn) file from paths instead of source code.
get_model_infoInspects a model without solving it: returns its solve method (satisfy/minimize/maximize) and the declared input parameters and output variables with their types. Useful for an agent to know exactly which params a model expects.
get_flatzincCompiles a model (and optional data) to FlatZinc text without solving it. Returns the .fzn model, the .ozn output model, and flattening statistics. Useful for debugging and low-level inspection.

solve_model arguments

ArgumentTypeDefaultDescription
model_codestr(required)The MiniZinc source code (.mzn) of the model.
paramsdict | strNoneParameter assignments like a .dzn file: a JSON object mapping names to values (a JSON string encoding such an object is also accepted).
solverstr"gecode"Which solver to use (see list_solvers).
all_solutionsboolFalseCompute all solutions of a solve satisfy problem.
max_solutionsint | NoneNoneStop after at most this many solutions.
timeout_secondsint | NoneNoneSolver time limit in seconds.

The result is a JSON object like:

{
  "status": "OPTIMAL_SOLUTION",
  "objective": 9,
  "solution": { "objective": 9, "x": 9, "y": 1 },
  "statistics": { "time": 0.204, "nodes": 3, ... }
}

status is one of SATISFIED, OPTIMAL_SOLUTION, ALL_SOLUTIONS, UNSATISFIABLE, UNKNOWN, or ERROR. validate_model and solve_model never raise in normal operation — errors are returned inside the result dict.


Developing locally

Clone the repo, then:

uv sync          # create the environment and install mcp + minizinc

The server speaks the MCP stdio transport, so it is launched as a subprocess by an MCP client. Run it with the SDK inspector:

uv run mcp dev server.py

that opens the MCP Inspector in the browser where every tool can be called interactively. A minimal programmatic smoke test:

uv run python -c "
import asyncio
from mcp import Client
from mcp.client.stdio import StdioServerParameters

async def main():
    params = StdioServerParameters(command='uv', args=['run', 'python', 'server.py'], cwd='.')
    async with Client(params) as client:
        result = await client.call_tool('solve_model', {
            'model_code': 'var 1..10: x; var 1..10: y; constraint x + y = 10; solve maximize x;'
        })
        print(result.content[0].text)

asyncio.run(main())
"

Running the tests

Install the test dependencies, then run the suite:

uv sync --group dev
uv run pytest -q

The tests in tests/ launch the server end-to-end over stdio and call every tool through the MCP protocol, solving the example model in example/. They need a working MiniZinc install (the same prerequisite as for developers).

Notes and limitations

  • params follows JSON representation: JSON arrays map to MiniZinc arrays; numbers, strings, and booleans map to their native MiniZinc types. Exotic types like sets and enums are not fully expressible this way.
  • Do not combine all_solutions with max_solutions; the MiniZinc driver rejects the combination.
  • MiniZinc requires a solver that supports the model (e.g. chuffed/gecode for CP, highs/cbc for MIP models). Use list_solvers to see what is installed.
  • Solutions are returned inline in the tool result; read_only_hint is set on all tools, so they do not modify your files or system.

Contributors

carban

15 commits

Languages

Python

90.2%

MiniZinc

9.8%