# CEMP 公共 HTTP MCP 使用说明

> 适用对象：Codex、Claude、支持 MCP Streamable HTTP 的 Agent，以及需要直接调用 HTTP 接口的开发者。  
> MCP 地址：`https://mcp.cleanenergymaterials.cn/mcp`  
> 注册用户登录：`https://mcp.cleanenergymaterials.cn/auth/login`  
> 文件上传地址：`https://mcp.cleanenergymaterials.cn/uploads`  
> 健康检查：`https://mcp.cleanenergymaterials.cn/health`

## 1. 服务是什么

CEMP 公共 HTTP MCP 把 CEMP 平台的自动计算、量子化学、结果绘图、性质预测和材料数据库查询能力封装为 25 个 MCP 工具。它支持两种账号模式：

- `anonymous`：不提供 Authorization，服务端使用共享的临时测试账号。所有匿名访问者共享权限和额度。
- `registered`：用户登录一次取得自己的 CEMP token，由客户端本机保存；后续请求携带 `Authorization: Bearer <token>`。调用使用该用户自己的权限、额度和 CEMP 审计记录。

> 当前匿名账号仅用于临时测试。建议在 [CEMP 官网注册页面](https://cleanenergymaterials.cn/register/register/) 注册账号，然后在 MCP 客户端配置自己的 token。

CEMP 平台继续负责：

- 权限判断和账号额度；
- 输入文件与业务参数校验；
- 自动计算任务排队和运行；
- `encrypted_id`、任务状态和结果下载；
- 业务错误和权限拒绝。

MCP 不绕过 CEMP 权限，不代理结果下载，也不维护任务所有权。服务端只持久化匿名共享账号的内部 token；注册用户的用户名、密码和 token 不在 MCP 服务器落盘，也不建立服务器端用户会话。

## 2. 三分钟快速接入

### 2.1 Codex：匿名临时测试

在终端执行：

```bash
codex mcp add cemp-tools \
  --url https://mcp.cleanenergymaterials.cn/mcp

codex mcp get cemp-tools --json
```

成功后，向 Agent 发出类似指令：

```text
列出 cemp-tools 提供的工具，并使用 polymer_predict_psmiles
预测 PSMILES *CC* 的聚合物性质。
```

删除配置时使用：

```bash
codex mcp remove cemp-tools
```

匿名工具调用的返回中固定包含：

```json
{
  "account_mode": "anonymous",
  "account_notice": "当前使用的是临时测试账号……https://cleanenergymaterials.cn/register/register/……"
}
```

这个提示不会阻止调用，只用于提醒匿名权限和额度是共享的。

### 2.2 Codex：注册用户一次登录、长期复用

登录接口接收一次 JSON 请求：

```http
POST https://mcp.cleanenergymaterials.cn/auth/login
Content-Type: application/json

{"username":"<CEMP 用户名>","password":"<CEMP 密码>"}
```

成功返回 `access_token`、`token_type=Bearer`、`account_mode=registered` 和 MCP 地址。响应带 `Cache-Control: no-store`。返回的是实际 CEMP token，必须像密码一样保管。

先在用户自己的电脑上执行一次交互式登录。下面的命令从终端读取用户名和密码，密码不会写入命令历史；响应 token 只进入当前终端的环境变量：

```bash
export CEMP_MCP_TOKEN="$(python3 /dev/fd/3 3<<'PY'
import getpass
import json
import sys
import urllib.request

sys.stderr.write("CEMP username: ")
sys.stderr.flush()
username = sys.stdin.readline().rstrip("\n")
password = getpass.getpass("CEMP password: ")
request = urllib.request.Request(
    "https://mcp.cleanenergymaterials.cn/auth/login",
    data=json.dumps({"username": username, "password": password}).encode("utf-8"),
    headers={"Content-Type": "application/json"},
    method="POST",
)
with urllib.request.urlopen(request, timeout=60) as response:
    print(json.load(response)["access_token"])
PY
)"
```

确认 token 已进入环境变量时只检查是否非空，不要打印 token：

```bash
test -n "$CEMP_MCP_TOKEN" && echo "CEMP token loaded"
```

然后注册 MCP：

```bash
codex mcp remove cemp-tools 2>/dev/null || true
codex mcp add cemp-tools \
  --url https://mcp.cleanenergymaterials.cn/mcp \
  --bearer-token-env-var CEMP_MCP_TOKEN

codex mcp get cemp-tools --json
```

`CEMP_MCP_TOKEN` 保存在用户机器上，不保存在 MCP 服务器上。它会由 MCP 客户端在每次请求中通过 HTTPS 发送。上面的 `export` 只对当前终端及其子进程有效；关闭终端后需要重新载入。若需要跨终端或重启长期使用，可把 token 放入本机密码管理器，或写入仅本人可读的本地环境文件并在启动 Codex 前加载。不要把 token 提交到 Git、聊天、截图或共享脚本。

最简单的本机持久化方式是在登录成功后保存一个 `0600` 环境文件：

```bash
mkdir -p "$HOME/.config/cemp-mcp"
chmod 700 "$HOME/.config/cemp-mcp"
umask 077
printf 'export CEMP_MCP_TOKEN=%q\n' "$CEMP_MCP_TOKEN" \
  > "$HOME/.config/cemp-mcp/token.env"
chmod 600 "$HOME/.config/cemp-mcp/token.env"
```

以后启动 Codex CLI 前只需加载，不需要再次输入账号密码：

```bash
source "$HOME/.config/cemp-mcp/token.env"
codex
```

也可以把 `source "$HOME/.config/cemp-mcp/token.env"` 加入本机 shell 启动配置。图形界面启动的客户端不一定继承终端环境变量，应按该客户端的本地环境变量机制配置；无论哪种方式，token 都保存在用户自己的机器上。

token 失效时，工具返回 `reauthentication_required`。重新执行登录命令并覆盖本机 `CEMP_MCP_TOKEN` 即可；服务不会自动切回匿名账号。

### 2.3 通用 MCP 客户端

匿名模式只需要 Streamable HTTP URL：

```json
{
  "mcpServers": {
    "cemp-tools": {
      "transport": "streamable-http",
      "url": "https://mcp.cleanenergymaterials.cn/mcp"
    }
  }
}
```

注册用户模式则在同一 URL 上增加 Bearer 认证。不同客户端的键名可能不同；下面是通用示意，实际应优先使用客户端的环境变量引用能力：

```json
{
  "mcpServers": {
    "cemp-tools": {
      "transport": "streamable-http",
      "url": "https://mcp.cleanenergymaterials.cn/mcp",
      "headers": {
        "Authorization": "Bearer ${CEMP_MCP_TOKEN}"
      }
    }
  }
}
```

不要把 CEMP 用户名或密码写入 MCP 配置。不要把 `/auth/login`、`/uploads` 或 `/health` 配置成 MCP URL。

### 2.4 协议连通性检查

健康检查：

```bash
curl --fail-with-body \
  https://mcp.cleanenergymaterials.cn/health
```

预期字段：

```json
{
  "status": "ok",
  "version": "1.1.0",
  "tools_count": 25,
  "cemp_connectivity": "reachable"
}
```

`/health` 正常只证明网关、MCP 进程和 CEMP 网站连通；它不证明某个账号权限、模型或长任务一定可用。

## 3. Agent 必须遵守的调用规则

建议把下面内容加入 Agent 的项目说明或系统提示：

```text
使用 cemp-tools 时：
1. 普通文本参数直接调用 MCP 工具。
2. 工具出现 excel_file、cif_file 或 files 参数时，不得虚构本地路径；
   必须先把本地文件以 multipart/form-data POST 到
   https://mcp.cleanenergymaterials.cn/uploads。
3. excel_file 和 cif_file 使用单个 upload_id；files 使用 upload_id 数组。
4. upload_id 只在 1 小时内有效，应在上传后立即调用工具。
5. 异步工具返回 encrypted_id 后必须保存，并用 get_task_status 查询。
6. 网络超时、5xx、upstream_timeout 或 upstream_network_error 表示结果可能未知；
   不得自动重新提交异步计算，以免产生重复任务。
7. permission_denied 由 CEMP 权限系统决定，不尝试在 MCP 侧绕过。
8. 结果下载继续使用 CEMP 返回的地址和既有语义，不自行猜测下载 URL。
9. 如果工具返回 `account_mode=anonymous`，提醒用户当前是临时共享测试账号，并给出注册链接
   https://cleanenergymaterials.cn/register/register/；不要阻断用户当前调用。
10. 如果返回 `reauthentication_required`，要求用户重新登录并更新本机 token；不得回退到匿名账号。
```

## 4. 文件上传

### 4.1 为什么需要单独上传

标准 MCP `tools/call` 是 JSON-RPC，请求体不能直接携带 multipart 文件。文件型工具采用两步流程：

```text
本地文件 ──multipart──> POST /uploads ──> upload_id
upload_id ──JSON-RPC──> MCP 工具 ───────> CEMP API
```

### 4.2 curl 上传

```bash
curl --fail-with-body \
  -F "file=@/absolute/path/System.xlsx" \
  https://mcp.cleanenergymaterials.cn/uploads
```

每次请求只能包含一个名为 `file` 的文件字段。成功响应固定为：

```json
{
  "upload_id": "<opaque-id>",
  "filename": "System.xlsx",
  "size_bytes": 12345,
  "sha256": "<hex>",
  "expires_at": "<ISO-8601>"
}
```

### 4.3 Python 上传

```python
from pathlib import Path

import requests

file_path = Path("/absolute/path/System.xlsx")
with file_path.open("rb") as handle:
    response = requests.post(
        "https://mcp.cleanenergymaterials.cn/uploads",
        files={"file": (file_path.name, handle)},
        timeout=300,
    )
response.raise_for_status()
upload_id = response.json()["upload_id"]
print(upload_id)
```

### 4.4 多文件工具

`draw_esp_gaussian`、`draw_esp_orca`、`draw_homo_lumo`、`nci_scf` 和 `nci_promolecular` 使用 `files` 数组。每个文件都必须分别上传：

```json
{
  "name": "draw_homo_lumo",
  "arguments": {
    "files": ["<upload-id-1>", "<upload-id-2>"]
  }
}
```

### 4.5 上传边界

- 单文件最大 1 GiB。
- `upload_id` 有效期 1 小时，有效期内可重复引用。
- 暂存区总容量为 20 GiB。
- 每 IP 每小时最多上传 10 个文件。
- 每 IP 最多同时上传 2 个文件。
- 不接受 Base64、用户电脑路径、Mac Studio 绝对路径或远程 URL。
- `upload_id` 是不透明标识符，必须原样使用，不能截断、改写或从文件名推导。
- 上传只表示临时文件接收成功，不表示文件已通过 CEMP 业务校验。

## 5. MCP 调用与返回结构

### 5.1 同步工具

同步工具会直接返回 JSON 结果或 CEMP 下载地址：

```json
{
  "tool_name": "polymer_predict_psmiles",
  "response_mode": "direct",
  "request_arguments": {"psmiles": "*CC*"},
  "payload": {"...": "CEMP 原始结果"},
  "message": "接口已直接返回 JSON 结果。"
}
```

如果 CEMP 返回结果文件，标准化结果还会包含 `download_url`。下载由 CEMP 处理，不经过 MCP 上传暂存区。

### 5.2 异步工具

异步工具提交成功后返回：

```json
{
  "tool_name": "mdcompute",
  "response_mode": "async",
  "encrypted_id": "<opaque-task-key>",
  "payload": {"...": "CEMP 原始提交响应"},
  "message": "任务已提交到后台，当前仅表示提交成功，不代表计算完成。"
}
```

调用者必须保存 `encrypted_id`。之后调用：

```json
{
  "name": "get_task_status",
  "arguments": {
    "encrypted_id": "<opaque-task-key>"
  }
}
```

常见任务状态包括 `not_finished`、`success` 和 `failed`。实际状态字段和结果地址以 CEMP 返回为准。

## 6. 工具总览

| 类别 | 工具数 | 工具 |
|---|---:|---|
| 状态查询 | 1 | `get_task_status` |
| MD 与长时分析 | 2 | `mdcompute`、`markov_gdynet_analysis` |
| Gaussian 自动计算 | 6 | 单点能、结合能、pKa/pKb、氧化还原、反应热力学、反应性质 |
| ORCA 自动计算 | 3 | 单点能、结合能、氧化还原 |
| 批量名称查询 | 1 | `query_smiles_to_name` |
| 波函数与 NCI 绘图 | 5 | ESP、HOMO/LUMO、两类 NCI |
| 性质预测 | 5 | 离子液体 2、聚合物 2、晶体 1 |
| 材料数据库 | 2 | 材料推荐、结构相似性查询 |

## 7. 全部 25 个工具说明

### 7.1 `get_task_status`

- 用途：根据异步任务提交后返回的密钥查询状态、结果信息和 CEMP 下载字段。
- 输入：`encrypted_id`，字符串，必填。
- 文件：不需要。
- 类型：同步查询；不会重新提交任务。
- 权限：由 CEMP 状态接口决定；MCP 不检查任务所属用户。
- 返回：`status`、CEMP 原始 `payload` 以及可能的结果地址。
- 最小调用：`{"encrypted_id":"<opaque-task-key>"}`。

### 7.2 `mdcompute`

- 用途：提交 GROMACS 分子动力学自动计算。
- 输入：`excel_file`，必填，值为 System.xlsx 上传后的单个 `upload_id`。
- 文件：必须符合 CEMP MD Excel 模板；不要直接传本地路径。
- 类型：异步。
- 权限：CEMP 自动计算接口实时判断。
- 返回：`encrypted_id`；随后调用 `get_task_status`。
- 最小调用：`{"excel_file":"<upload-id>"}`。

### 7.3 `markov_gdynet_analysis`

- 用途：对已经成功完成的 CEMP MD 任务提交 Markov/GDyNet 长时间尺度分析。
- 输入：`md_task_id`，必填，填写已完成 MD 任务的 `encrypted_id`。
- 文件：不需要重新上传轨迹；CEMP 根据已有 MD 任务定位数据。
- 类型：异步，会产生新的 `encrypted_id`。
- 权限：`auto_compute_permission`，由 CEMP 判断。
- 最小调用：`{"md_task_id":"<completed-md-task-key>"}`。
- Agent 注意：不要绕过 CEMP 队列直接 SSH 到计算节点。

### 7.4 `single_point_energy_gaussian`

- 用途：批量提交 Gaussian 单点能计算。
- 输入：`excel_file`，必填，单个 `upload_id`。
- 类型：异步；权限为 CEMP `gaussian_permission`。
- 返回：`encrypted_id`。
- 最小调用：`{"excel_file":"<upload-id>"}`。

### 7.5 `binding_energy_gaussian`

- 用途：批量提交 Gaussian 结合能计算。
- 输入：`excel_file`，必填，二聚体 Excel 的 `upload_id`。
- 类型：异步；权限为 CEMP `gaussian_permission`。
- 返回：`encrypted_id`。
- 最小调用：`{"excel_file":"<upload-id>"}`。

### 7.6 `pka_pkb_gaussian`

- 用途：提交 Gaussian pKa/pKb 计算。
- 输入：`excel_file`，必填，酸/共轭碱 Excel 的 `upload_id`。
- 类型：异步；权限为 CEMP `gaussian_permission`。
- 返回：`encrypted_id`。
- 最小调用：`{"excel_file":"<upload-id>"}`。

### 7.7 `ox_red_gaussian`

- 用途：提交 Gaussian 氧化还原电位计算。
- 输入：`excel_file`，必填，Excel 的 `upload_id`。
- 类型：异步；权限为 CEMP `gaussian_permission`。
- 返回：`encrypted_id`。
- 最小调用：`{"excel_file":"<upload-id>"}`。

### 7.8 `reaction_thermo_gaussian`

- 用途：提交 Gaussian 反应热力学量计算。
- 输入：`excel_file`，必填，严格按 CEMP 模板填写后的 `upload_id`。
- 类型：异步；权限为 CEMP `gaussian_permission`。
- 返回：`encrypted_id`。
- Agent 注意：当前公开材料没有完整定义所有表格校验规则，不要自行臆造列名。

### 7.9 `reaction_properties_gaussian`

- 用途：提交 Gaussian 反应活性或反应位点性质计算。
- 输入：`excel_file`，必填，CEMP 模板 Excel 的 `upload_id`。
- 类型：异步；权限为 CEMP `gaussian_permission`。
- 返回：`encrypted_id`。
- Agent 注意：模板与说明页不一定一一对应，应使用 CEMP 提供的当前模板。

### 7.10 `single_point_energy_orca`

- 用途：批量提交 ORCA 单点能计算。
- 输入：`excel_file`，必填，单个 `upload_id`。
- 类型：异步；权限由 CEMP ORCA 接口判断。
- 返回：`encrypted_id`。

### 7.11 `binding_energy_orca`

- 用途：批量提交 ORCA 结合能计算。
- 输入：`excel_file`，必填，单个 `upload_id`。
- 类型：异步；权限由 CEMP ORCA 接口判断。
- 返回：`encrypted_id`。

### 7.12 `ox_red_orca`

- 用途：提交 ORCA 氧化还原电位计算。
- 输入：`excel_file`，必填，单个 `upload_id`。
- 类型：异步；权限由 CEMP ORCA 接口判断。
- 返回：`encrypted_id`。

### 7.13 `query_smiles_to_name`

- 用途：上传含 SMILES 的 Excel，批量查询分子名称。
- 输入：`excel_file`，必填，单个 `upload_id`。
- 类型：异步；权限由 CEMP 查询接口判断。
- 返回：`encrypted_id`，任务完成后通常得到处理后的结果表。
- Agent 注意：不要假设结果一定包含 `all_results.zip`。

### 7.14 `draw_esp_gaussian`

- 用途：根据 Gaussian 波函数绘制 ESP 静电势。
- 输入：`files`，必填，包含一个或多个 `upload_id` 的数组。
- 推荐文件：`.fchk`；`.chk` 仅保证兼容 Gaussian16 生成的文件。
- 类型：异步；返回 `encrypted_id`。
- 最小调用：`{"files":["<upload-id>"]}`。

### 7.15 `draw_esp_orca`

- 用途：根据 ORCA 波函数绘制 ESP 静电势。
- 输入：`files`，必填，`upload_id` 数组。
- 推荐文件：`.molden`；`.gbw` 仅保证兼容 ORCA 6.0.1 生成的文件。
- 类型：异步；返回 `encrypted_id`。

### 7.16 `draw_homo_lumo`

- 用途：根据 Gaussian 或 ORCA 波函数绘制 HOMO/LUMO 轨道。
- 输入：`files`，必填，`upload_id` 数组。
- 类型：异步；返回 `encrypted_id`。
- 多文件：需要先逐个上传，再按顺序组装数组。

### 7.17 `nci_scf`

- 用途：基于真实 SCF 波函数执行 NCI 分析。
- 输入：`files`，必填，Gaussian/ORCA 波函数文件的 `upload_id` 数组。
- 类型：异步；返回 `encrypted_id`。
- 与 `nci_promolecular` 的区别：本工具依赖 SCF 波函数。

### 7.18 `nci_promolecular`

- 用途：基于 promolecular 近似执行 NCI 分析。
- 输入：`files`，必填，结构文件的 `upload_id` 数组。
- 类型：异步；返回 `encrypted_id`。
- 与 `nci_scf` 的区别：本工具不要求 SCF 波函数。

### 7.19 `ionic_liquid_predict_excel`

- 用途：批量预测离子液体性质。
- 输入：`excel_file`，必填，Excel 的 `upload_id`。
- 类型：同步。
- 权限：CEMP 机器学习接口实时判断。
- 返回：通常包含 `download_url`，无需轮询任务状态。

### 7.20 `ionic_liquid_predict_smiles`

- 用途：预测单个离子液体 SMILES 的性质。
- 输入：`smiles`，字符串，必填。
- 文件：不需要。
- 类型：同步，直接返回预测 JSON。
- 最小调用：`{"smiles":"C[N+](C)(C)C.[Cl-]"}`。

### 7.21 `polymer_predict_excel`

- 用途：批量预测聚合物性质。
- 输入：`excel_file`，必填，Excel 的 `upload_id`。
- 类型：同步。
- 返回：通常包含 CEMP `download_url`，无需轮询。

### 7.22 `polymer_predict_psmiles`

- 用途：预测单个均聚物 PSMILES 的性质。
- 输入：`psmiles`，字符串，必填。
- 文件：不需要。
- 类型：同步，直接返回预测 JSON。
- 最小调用：`{"psmiles":"*CC*"}`。
- Agent 注意：不要把配方表或多组分共聚体系当作单一 PSMILES。

### 7.23 `crystal_predict_excel`

- 用途：上传单个 CIF 并预测晶体性质。
- 输入：`cif_file` 必填，值为单个 `upload_id`；`model_select` 可选，默认 `GAT`。
- 远端 multipart 字段由 MCP 自动转换，调用者只使用公开参数名。
- 类型：同步，直接返回预测 JSON。
- 最小调用：`{"cif_file":"<upload-id>"}`。
- 显式模型调用：`{"cif_file":"<upload-id>","model_select":"GAT"}`。

### 7.24 `material_recommendation_search`

- 用途：根据自然语言材料目标检索并排序 CEMP 候选材料。
- 文件：不需要。
- 类型：同步，直接返回候选池 JSON。
- 权限：CEMP `database_permission`。
- 参数：
  - `query`：字符串，必填，材料目标或筛选需求。
  - `domains`：字符串数组，可选，默认 `["auto"]`；可用 `auto`、`ionic_liquid`、`polymer`、`crystal`。
  - `topk_pool`：整数，可选，默认 40，范围 1–200。
  - `seed_molecules`：对象数组，可选；每项可含 `name` 和 `smiles`。
- 最小调用：

  ```json
  {
    "query": "高电导率、低熔点的离子液体",
    "domains": ["ionic_liquid"],
    "topk_pool": 20
  }
  ```

### 7.25 `molecule_property_similarity_search`

- 用途：用分子 SMILES 或聚合物 PSMILES 查询精确结构、相似结构及其性质。
- 文件：不需要。
- 类型：同步，直接返回匹配结果 JSON。
- 权限：CEMP `database_permission`。
- 参数：
  - `smiles`：字符串，必填，可为 SMILES 或 PSMILES。
  - `topk`：整数，可选，默认 3，范围 1–50。
  - `method`：可选，当前只支持 `tanimoto`。
  - `radius`：Morgan 指纹半径，默认 2，范围 1–4。
  - `n_bits`：Morgan 指纹位数，默认 2048，范围 128–8192。
- 最小调用：`{"smiles":"CCO","topk":3}`。

## 8. 三套完整工作流

### 8.1 数据库相似性查询

1. 确认客户端发现 `molecule_property_similarity_search`。
2. 调用：

   ```json
   {
     "name": "molecule_property_similarity_search",
     "arguments": {
       "smiles": "CCO",
       "topk": 3,
       "method": "tanimoto"
     }
   }
   ```

3. 从 `payload` 读取精确匹配、相似结构、性质、来源数据库和相似度。
4. 如果返回 `permission_denied`：注册用户应在 CEMP 检查自己的权限；匿名用户只能联系维护者调整共享测试账号权限。
5. 如果返回上游超时或 5xx，不要把错误当作“数据库无结果”。

### 8.2 PSMILES 聚合物性质预测

1. 准备单个均聚物 PSMILES，例如 `*CC*`。
2. 调用：

   ```json
   {
     "name": "polymer_predict_psmiles",
     "arguments": {"psmiles": "*CC*"}
   }
   ```

3. 从 `payload` 读取 CEMP 当前返回的 Tg、Tm、介电常数、杨氏模量、拉伸强度等字段。
4. 预测字段、单位和可用模型以 CEMP 实际响应为准，Agent 不补造缺失字段。

### 8.3 Excel 上传、MD 提交和状态查询

1. 下载或准备符合 CEMP 要求的 System.xlsx。
2. 在用户本地上传：

   ```bash
   curl --fail-with-body \
     -F "file=@/absolute/path/System.xlsx" \
     https://mcp.cleanenergymaterials.cn/uploads
   ```

3. 保存响应中的 `upload_id`，在 1 小时内调用：

   ```json
   {
     "name": "mdcompute",
     "arguments": {"excel_file": "<upload-id>"}
   }
   ```

4. 成功时立即保存 `encrypted_id`。
5. 查询任务：

   ```json
   {
     "name": "get_task_status",
     "arguments": {"encrypted_id": "<opaque-task-key>"}
   }
   ```

6. `not_finished` 表示继续等待；`success` 表示读取 CEMP 返回的结果字段；`failed` 表示查看 CEMP 业务错误。
7. 提交请求超时或结果未知时，禁止重新提交同一任务；先利用已经保存的信息核查。

## 9. 限额

| 范围 | 限额 |
|---|---:|
| 注册用户登录 | 每 IP 每小时 10 次 |
| 普通 MCP 请求 | 每 IP 每分钟 60 次 |
| 异步计算提交 | 每 IP 每小时 5 次 |
| multipart 上传 | 每 IP 每小时 10 个文件 |
| 同时上传 | 每 IP 最多 2 个 |
| 单文件 | 最大 1 GiB |
| 上传暂存区 | 全局 20 GiB |
| 上传有效期 | 1 小时 |

异步提交同时计入普通 MCP 请求限额。服务重启会清空 MCP 进程内限流计数，但不会绕过 CEMP 自身的额度限制。

## 10. 错误处理

| 错误码 | 含义 | Agent 应采取的动作 |
|---|---|---|
| `invalid_upload_id` | ID 格式非法，或提交了路径、URL、Base64、错误数组形状 | 重新上传并原样使用 ID |
| `upload_not_found` | ID 不存在、伪造或上传残缺 | 重新上传 |
| `upload_expired` | ID 已超过 1 小时 | 重新上传 |
| `empty_file` | 文件为空 | 生成有效文件后上传 |
| `file_too_large` | 单文件超过 1 GiB | 缩小输入或拆分任务 |
| `upload_storage_full` | 20 GiB 暂存区不足 | 等待过期清理后再上传 |
| `upload_rate_limited` | 每小时上传次数超限 | 按 `Retry-After` 等待 |
| `upload_concurrency_limited` | 同时上传超过 2 个 | 等待当前上传结束 |
| `invalid_login_request` | 登录 JSON、字段或 Content-Type 非法 | 提交 username/password JSON |
| `invalid_credentials` | CEMP 用户名或密码无效 | 检查凭据后重新登录 |
| `login_rate_limited` | 每 IP 每小时登录超过 10 次 | 按 `Retry-After` 等待 |
| `invalid_authorization` | Authorization 不是合法 Bearer 格式 | 修正客户端认证配置 |
| `rate_limited` | MCP 或异步提交频率超限 | 按 `Retry-After` 等待 |
| `permission_denied` | CEMP 拒绝当前调用账号的权限 | 注册用户检查自己的权限；匿名用户联系维护者 |
| `authentication_failed` | 服务端共享认证失败 | 联系维护者，不要求用户提交账号密码 |
| `reauthentication_required` | 注册用户 token 已失效 | 重新登录并覆盖本机 token，不回退匿名账号 |
| `auth_upstream_timeout` | CEMP 登录请求超时 | 稍后重新登录 |
| `auth_upstream_unavailable` | 暂时无法连接 CEMP 登录服务 | 稍后重新登录 |
| `upstream_timeout` | CEMP 超时，结果未知 | 不自动重试异步任务 |
| `upstream_network_error` | 网络结果未知 | 不自动重试异步任务 |
| `upstream_error` | CEMP 返回 5xx | 稍后核查，异步任务不自动重提 |
| CEMP 原始业务错误 | 输入、额度或业务规则失败 | 根据 CEMP 错误修改输入 |

### 10.1 哪些情况可以重试

- 上传明确返回 `upload_not_found` 或 `upload_expired`：重新上传文件。
- 限流明确返回 `Retry-After`：等待对应时间后重试。
- 同步只读查询明确失败且没有产生任务：可以由用户决定稍后重试。

### 10.2 哪些情况不能自动重试

- 任意异步工具提交发生客户端超时。
- CEMP 返回 5xx，但无法确定是否已经受理任务。
- 网络连接在提交后中断。
- 客户端只看到“结果未知”。

这些情况自动重提可能创建重复计算任务并重复消耗共享额度。

## 11. 隐私和安全边界

- 服务公开，任何能访问域名的人都能发现并调用工具。
- 客户端不需要也不应获得共享 CEMP 凭据或 token。
- 注册用户的账号密码只用于当前 HTTPS 登录请求；MCP 服务器不持久化它们。
- 注册用户 token 保存在用户自己的机器上，并随每次 MCP 请求通过 HTTPS 发送；服务器只在当前请求内读取和转发，不落盘、不写日志。
- 此 token 是真实 CEMP token，也可能直接用于 CEMP API。持有者等同于账号本人；不要复制到聊天、Git、日志或共享配置。
- 日志不记录请求正文、文件内容、完整参数、凭据、token 或完整 `upload_id`。
- 上传文件在临时区保存 1 小时，不按用户隔离；持有 `upload_id` 即可在有效期内引用。
- `encrypted_id` 的访问和下载语义完全沿用 CEMP。
- MCP 不接受用户输入的服务器文件路径，不把用户字符串拼接成文件系统路径。
- HTTPS 是唯一公网入口；VPS 上游端口不允许公网直连。

不要上传超出 CEMP 业务需要的敏感信息。匿名共享账号的 CEMP 审计无法区分不同公网调用者；注册用户模式则使用自己的 CEMP 审计身份。

## 12. 故障排查

### 12.1 客户端发现不了工具

1. 确认 URL 精确为 `https://mcp.cleanenergymaterials.cn/mcp`。
2. 确认客户端支持 Streamable HTTP，而不是只支持 stdio 或旧版 SSE。
3. 访问 `/health`，确认 `tools_count` 为 25。
4. 删除重复或旧配置后重新添加 MCP。
5. 检查本机 MCP 客户端配置本身能否被正常解析。

### 12.2 Agent 声称找不到本地文件

这是预期行为。远程 MCP 无法读取用户电脑路径。Agent 应先在本地构建文件，使用 `/uploads` 上传，再把 `upload_id` 交给工具。

### 12.3 上传成功但工具报输入错误

上传接口只检查文件存在、大小和暂存安全，不检查 Excel 列名、CIF 内容或量子化学文件版本。业务格式由 CEMP endpoint 校验。

### 12.4 `/health` 正常但某工具失败

`/health` 不检查每一个模型和队列。继续读取结构化错误：权限问题看 `permission_denied`，网络问题看 `upstream_*`，业务问题看 CEMP 原始错误码。

### 12.5 数据库查询超时

不要把超时解释为“没有匹配”。数据库接口可能仍在 CEMP 上游计算或等待；根据错误码决定稍后进行一次新的只读查询，不要连带重提异步计算。

### 12.6 已登录但返回 `reauthentication_required`

本机保存的 token 已被 CEMP 判定为无效或过期。重新调用 `POST /auth/login`，覆盖本机 `CEMP_MCP_TOKEN`，并重启或重新连接 MCP 客户端以载入新值。服务不会把这次请求改用匿名账号。

## 13. Agent 复用检查表

调用前：

- [ ] MCP URL 是 `/mcp`。
- [ ] 已明确选择匿名模式或注册用户模式。
- [ ] 注册用户只在本机保存 token，没有把用户名密码写入 MCP 配置。
- [ ] 匿名结果中的临时测试提示及 CEMP 注册链接已正确传达给用户。
- [ ] 已通过 `tools/list` 发现目标工具。
- [ ] 已区分同步工具和异步工具。
- [ ] 文件型工具已经完成 `/uploads`。
- [ ] 使用的是完整、未改写且未过期的 `upload_id`。

调用后：

- [ ] 同步结果读取 `payload` 或 `download_url`。
- [ ] 异步结果已经保存 `encrypted_id`。
- [ ] 状态查询只调用 `get_task_status`，没有重复提交原任务。
- [ ] 错误按结构化错误码处理。
- [ ] 没有在日志、聊天或公开文件中复制共享凭据。
- [ ] 没有打印、记录或提交注册用户 token。

## 14. 服务维护摘要

- Mac Studio HTTP 服务：LaunchAgent `cn.cleanenergymaterials.cemp-tools-mcp`。
- Mac Studio FRP：独立 LaunchAgent `cn.cleanenergymaterials.frpc-cemp-mcp`。
- MCP 只监听 Mac Studio `127.0.0.1:18082`。
- VPS Nginx 只通过 `127.0.0.1:18082` 访问 FRP 上游。
- HTTPS 证书由 Certbot 定时器自动检查续签。
- Certbot 成功续签后通过部署钩子执行 `nginx -t`，通过后平滑 reload。
- stdio 入口继续保留，与 HTTP 状态目录分离。

维护者检查命令：

```bash
curl --fail-with-body https://mcp.cleanenergymaterials.cn/health
systemctl is-enabled certbot-renew.timer
systemctl is-active certbot-renew.timer
certbot renew --cert-name mcp.cleanenergymaterials.cn \
  --dry-run --no-random-sleep-on-renew --run-deploy-hooks
```

证书续签测试不应与真实业务任务混在同一个重试流程中。配置修改必须先执行 `nginx -t`，只有成功后才能 reload。

## 15. 地址速查

| 地址 | 用途 |
|---|---|
| `https://mcp.cleanenergymaterials.cn/` | HTML 使用说明 |
| `https://mcp.cleanenergymaterials.cn/guide.md` | Agent 可直接读取的 Markdown 手册 |
| `https://mcp.cleanenergymaterials.cn/mcp` | MCP Streamable HTTP |
| `https://mcp.cleanenergymaterials.cn/auth/login` | 注册用户用账号密码换取 CEMP token |
| `https://mcp.cleanenergymaterials.cn/uploads` | 单文件 multipart 上传 |
| `https://mcp.cleanenergymaterials.cn/health` | 最小健康检查 |
| `https://cleanenergymaterials.cn/register/register/` | CEMP 官网注册页面 |
