内容
# mcp-decision-lab

**用于结构化决策的MCP服务器 — 加权决策矩阵、标准评分、敏感性分析以及可靠的推荐。**
## 为什么
大型语言模型(LLMs)擅长列出优缺点,然后选择感觉“正确”的选项。这种推理是不透明的、不稳定的,难以审计:改变提示中的一个形容词,答案就会翻转。mcp-decision-lab是一个**思维工具** — 模型使用它将自己的推理结构化为显式的加权决策矩阵。每个分数都需要有书面理由,权重标准化且透明,最终的`analyze`步骤进行真正的数学运算:精确的(封闭形式,非暴力)敏感性分析,告诉你**哪个标准权重会翻转获胜者以及在什么值** — 因此推荐带有稳健性判决而不是凭直觉。
## 工具
| 工具 | 参数 | 返回值 |
| --- | --- | --- |
| `start_decision` | `question: str`, `options: list[str]`(≥2),`criteria: list[dict]`(≥2,每个`{"name", "weight", "higher_is_better"?}`) | 新的`decision_id`,标准化权重为1.0的权重,空白单元格列表,下一步指令 |
| `score_option` | `decision_id`,`option`,`criterion`,`score: float`(0–10),`rationale: str`(≥10 chars,需要) | 记录的单元格,剩余缺失单元格,下一步 |
| `get_matrix` | `decision_id` | 完整矩阵:原始分数,有效分数,加权分数,每项选择总分,理由,缺失单元格 |
| `analyze` | `decision_id`(矩阵必须完整) | 排名 + 边距,每个标准的敏感性(精确翻转权重,方向,新获胜者,决定性标志),每个选项的优势/劣势,稳健性判决(`robust`/`fragile`),文本推荐 |
| `list_decisions` | — | 所有会话状态:`pending` / `complete` / `analyzed` |
标准中原始分数高表示*坏*(成本,风险,复杂性)取`"higher_is_better": false` — 有效分数自动变为`10 - score`。
## 工作原理
```mermaid
flowchart TD
A[start_decision<br/>问题 + 选项 + 加权标准] --> B[权重标准化为1.0<br/>会话 dec-xxxx 持久化到磁盘]
B --> C[评估选项 x N<br/>一个单元格 = 选项 x 标准,<br/>分数 0-10 + 必须有理由]
C -->|单元格缺失| C
C -->|矩阵完整| D[get_matrix<br/>查看原始 / 加权分数]
D --> E[分析]
E --> F[排名 + 边距<br/>加权总分]
E --> G["敏感性分析<br/>封闭形式翻转每个标准的权重:<br/>求解 gap(w') = w'·d + (1-w')·r = 0"]
E --> H[优势 / 劣势<br/>每个选项的最佳和最差标准]
F --> I[稳健性判决<br/>稳健 vs 脆弱 under ±50% 权重变化]
G --> I
H --> I
I --> J[可靠的推荐]
```
**敏感性数学。** 使用标准化权重,将标准 *c* 的权重从 *w* 更改为 *w′* (按比例重新标准化其他权重)使得每个选项的总分 **线性** 地变为 *w′*。对于获胜者 A 与挑战者 B 之间的差距为 `gap(w′) = w′·d + (1−w′)·r`,其中 `d` 是它们在 *c* 上的有效分数差,`r` 是它们在其他权重上的缩放差异。求解 `gap(w′) = 0` 得到精确的翻转权重 `w* = r/(r−d)` — 仅当存在区间 `[0, 1]` 时才报告,其中挑战者严格获胜。如果任何单个权重的 ±50% 相对变化不会改变获胜者,则判决为 **稳健**;否则为 **脆弱**,并指定决策所依赖的标准。
## 快速开始
```bash
pip install -e .
```
**Claude Desktop** — 添加到 `claude_desktop_config.json`:
```json
{
"mcpServers": {
"decision-lab": {
"command": "python",
"args": ["/absolute/path/to/server.py"]
}
}
}
```
**Claude 代码:**
```bash
claude mcp add decision-lab -- python /absolute/path/to/server.py
```
会话以 `~/.mcp-decision-lab/decisions.json` 中的 JSON 形式保存(使用环境变量 `DECISION_LAB_DIR` 覆盖目录)。
## 示例会话
> **用户:** 帮助我为新的SaaS后端选择数据库 — Postgres、MongoDB 或 DynamoDB。成本最重要,其次是可扩展性,然后是团队熟悉程度。
模型启动了一个会话:
```python
start_decision(
question="Which database should we use for the new SaaS backend?",
options=["Postgres", "MongoDB", "DynamoDB"],
criteria=[
{"name": "cost", "weight": 0.5, "higher_is_better": False},
{"name": "scalability", "weight": 0.3},
{"name": "team-familiarity", "weight": 0.2},
],
)
# → {"decision_id": "dec-34b5", "cells_total": 9,
# "next_step": "Score each option against each criterion using score_option ..."}
```
然后对所有9个单元格进行评分,每个单元格都有理由:
```python
score_option("dec-34b5", "Postgres", "cost", 3,
"Managed Postgres (RDS/Neon) is cheap and predictable at our scale")
score_option("dec-34b5", "DynamoDB", "scalability", 10,
"Effectively unlimited managed horizontal scale")
score_option("dec-34b5", "DynamoDB", "team-familiarity", 4,
"Only one engineer knows single-table design patterns")
# ... 6 more cells ...
# → {"missing_cells": [], "next_step": "Matrix complete — call analyze('dec-34b5') ..."}
```
并分析:
```python
analyze("dec-34b5")
```
```json
{
"ranking": [
{"rank": 1, "option": "Postgres", "total": 7.1},
{"rank": 2, "option": "DynamoDB", "total": 5.8},
{"rank": 3, "option": "MongoDB", "total": 5.6}
],
"winner": "Postgres",
"margin": 1.3,
"sensitivity": [
{"criterion": "cost", "weight": 0.5, "decisive": true,
"flip": {"flip_weight": 0.1176, "direction": "decrease",
"new_winner": "DynamoDB", "within_50pct_band": false}},
{"criterion": "scalability", "weight": 0.3, "decisive": true,
"flip": {"flip_weight": 0.4717, "direction": "increase",
"new_winner": "DynamoDB", "within_50pct_band": false}},
{"criterion": "team-familiarity", "weight": 0.2, "decisive": false, "flip": null}
],
"decisive_criteria": ["cost", "scalability"],
"robustness": "robust",
"recommendation": "Choose Postgres (7.1 weighted) over DynamoDB (5.8); margin 1.3. Postgres is strongest on 'team-familiarity' (9/10) and weakest on 'scalability' (6/10). The result is robust: no ±50% relative change to any single criterion weight changes the winner. (Extreme shifts could still flip it: 'cost' would have to decrease from 0.5 to 0.1176 for DynamoDB to win; 'scalability' would have to increase from 0.3 to 0.4717 for DynamoDB to win.)"
}
```
> **模型(对用户):** Postgres 以 7.1 加权获胜,而 DynamoDB 为 5.8,结果稳健:没有合理的(±50%)单个权重变化会改变获胜者。如果可扩展性价值确实为 ~0.47 而非 0.3 — 或者成本降至 ~0.12 — DynamoDB 将超越。如果您确实期望极端扩展,请重新评估;否则 Postgres 是可靠的选择。
## 开发
```bash
pip install -e ".[dev]"
python -m pytest
```
测试仅需 `core.py` 即可运行,无需安装 `mcp` 包。
## License
MIT