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.
README
load-planner-mcp
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:
explaintakes 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.- The stored record holds the solver result only.
solvediscards the problem payload once the solver has run. There is no field on the stored record that could carry an input value. - There is no arithmetic on the
explainpath. 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_idfrom 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.solveruns 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.pyare 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_narrationchecks that every number in a narration appears in the result. It does not check that the number was used to mean the right thing.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。