Load Planner MCP

Load Planner MCP

Enables optimal freight-mode selection (air, sea-LCL, full container) by solving 3D bin-packing, cost optimization, and delivery-risk analysis behind two tools: solve for deterministic planning and explain for hallucination-proof natural-language narration of results.

Category
Visit Server

README

load-planner-mcp

CI

A deterministic load-planning solver, plus an MCP stdio server that exposes it as two tools. The solver decides freight mode for a cohort of orders — all-air, consolidated sea-LCL, or full container — prices each option, and attaches a risk read (ETA percentiles, deadline-miss probability, CVaR of the delay tail).

What is in here

Path Contents
load_planner/geometry.py 3D bin-packing (py3dbp): do the pallets fit a 20GP/40GP/40HC, and at what fill rate
load_planner/solver.py Fixed-charge MILP over OR-Tools CP-SAT: cheapest feasible assignment per enumerated mode-pattern
load_planner/risk.py Delay-distribution convolution: p50/p90 ETA, deadline-miss probability, CVaR(alpha)
load_planner/scenarios.py Enumerates the cards, scores them on one identical vector, ranks them, picks a recommendation
load_planner/cli.py A plain stdin/stdout JSON boundary, for hosts that prefer a child process to an import
solver_mcp/server.py The MCP stdio server: JSON-RPC 2.0, two tools, and verify_narration()
fixtures/cohort_urgent.json A synthetic 20-pallet cohort with a synthetic rate card, used by the tests

The two sub-problems are layered rather than merged. Solving true 3D placement inside the MILP explodes combinatorially, so the packer runs first and hands CP-SAT a fill rate and a feasibility flag.

The two-tool contract

solve(problem) runs the solver and returns its output verbatim — not reformatted, not rounded, not summarised — together with a result_id and a SHA-256 content_hash of the result. The result is kept in an in-process store.

explain(result_id) returns a narration built from a fixed template whose slots are filled from that stored result.

The split is the design. A language model calling this server chooses what to solve and puts the answer into words; it does not originate any figure. Three properties make that structural rather than aspirational:

  1. explain takes one opaque id and nothing else. Its input schema has a single property. It cannot be handed a rate, a weight or a deadline, so it cannot restate one.
  2. The stored record holds the solver result only. solve discards the problem payload once the solver has run. There is no field on the stored record that could carry an input value.
  3. There is no arithmetic on the explain path. Values are looked up by key and rendered as strings. Selecting the recommended card reads a flag the solver already set; it does not compare or compute.

verify_narration(narration, stored) turns the claim into a check. It scans the text for digit runs and rejects any token absent from the stored result, so a narration that rounds 11480.0 to "11500", converts 0.1246 to "12.46%", or adds two stored costs together fails — each of those is a number the solver never produced. A host can apply it to any narration before display, including one the model wrote in its own words rather than one explain returned. explain runs it on its own output before returning.

What the guard deliberately allows, so it is not mistaken for a stronger claim: digits inside stored strings and dict keys count as present, because a narration may quote those strings verbatim. "ortools-cpsat+py3dbp" admits 3, and the field name eta_p90_days admits 90. It is a lexical check on numeric tokens, not a proof of semantic correctness: a narration that attaches the right number to the wrong label still passes.

Install

Python 3.10 or newer.

python -m venv .venv
./.venv/bin/pip install ortools py3dbp pytest

Or install the package itself, which pulls the two runtime dependencies:

pip install -e .

ortools is the CP-SAT engine; py3dbp is the 3D packer, MIT-licensed. The MCP server adds nothing beyond the standard library — the stdio protocol surface is small enough to implement directly, which keeps the dependency list auditable.

Run

The server speaks newline-delimited JSON-RPC 2.0 on stdin/stdout:

python -m solver_mcp

The solver is also usable without MCP, as a library or as a child process:

from load_planner import generate_scenarios
result = generate_scenarios(problem)
cat fixtures/cohort_urgent.json | python -m load_planner.cli

Wiring into an MCP client

Any client that launches stdio servers takes a command and arguments. For a client using the common mcpServers configuration shape:

{
  "mcpServers": {
    "load-planner": {
      "command": "/absolute/path/to/.venv/bin/python",
      "args": ["-m", "solver_mcp"],
      "env": { "PYTHONPATH": "/absolute/path/to/load-planner-mcp" }
    }
  }
}

PYTHONPATH is only needed when the package has not been installed into the interpreter's environment; after pip install -e . the env block can go.

The handshake is the standard one: initialize, then the notifications/initialized notification, then tools/list. The server reports protocol version 2025-06-18 and accepts 2025-03-26 and 2024-11-05, echoing back whichever the client asked for if it is one of those.

Tests

python -m pytest tests/ -q

Three suites: the solver's own tests against the fixture; the MCP handshake and both tools, exercised in process and over a real stdio subprocess; and the tamper suite, which asserts that a narration containing a value absent from the stored result is rejected.

Limits

  • Single machine, single process. The result store is in memory and lives for the life of the server process. A result_id from one process resolves in another only because ids are content-addressed and the solver is deterministic — re-solving the same problem reproduces the id. There is no shared store, no eviction, and no bound on the number of retained results.
  • Solver runtimes. CP-SAT is called once per enumerated mode-pattern, at most three times per solve, on a model with one integer variable and two constraints; it returns in milliseconds. The cost that scales is the 3D packer, which places one item per pallet — a few hundred pallets is fine, tens of thousands is not. solve runs synchronously and has no internal timeout, so a host should impose its own.
  • Whole-order assignment only. Splitting one order across two modes (a base-plus-surge policy) is not modelled; each order is assigned entirely to one mode.
  • Seeded risk inputs. The delay distributions in risk.py are published carrier-reliability seeds, not measurements from your own lane history. They are the right shape and the wrong precision until a caller replaces them.
  • The guard is lexical. See the note above: verify_narration checks that every number in a narration appears in the result. It does not check that the number was used to mean the right thing.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured