Files
tmp/se-agent-mcp-tool.md
T
2026-09-23 11:20:51 +08:00

1221 lines
63 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SE 工作流 MCP 工具 API 文档
> **来源**:`docs/task/se工作流mcp工具统计.md`(草稿统计)→ 本文档按 `mis-mcp-server` **源码实现**补全为可调用的 API 文档
> **覆盖范围**:SE 工作流相关的 **9 个** MCP 工具
> **生成日期**:2026-09-22
> **代码基线**:`mis-mcp-server` 分支 `dev`
>
> **一句话定位**:面向「AI 生成 SKILL / Prompt」场景的机器友好型接口文档。每个工具给出**参数表 + 返回 JSON 结构 + 字段语义 + 关联工具**。
### 修订记录(2026-09-22)
编写本文档时发现 **5 处工具描述与实现不符**,已在 `mis-mcp-server` 侧修正(**未改动 `mbx` 下游代码**):
| 工具 | 原描述问题 | 处置 |
|---|---|---|
| `queryDriverListVersion` | 说「驱动列表唯一标识」「返回 `packageFileUrl` 即可」——实为**版本**标识,且该字段**嵌套**在数组里、未裁剪 | ✅ 改描述 |
| `queryTestUnitListByProjectName` | 说「根据项目名称、**五码**查询」——下游 SQL **未按五码过滤** | ✅ 改描述 + 参数说明 |
| `queryProjectNameList` | 说「获取项目名称列表」——实为**固定最多 2 条** | ✅ 常量 `2` → `100`,并同步描述(**行为变更**) |
| `queryTestPcByUuids` | 未说明在线状态字段名——直觉会取恒为 null 的 `onlineStatus` | ✅ 描述里点明用 `onlineStatusKey` |
| `creatOrSendTask` | 未说明 `other.type` 必填——漏传会下游报错 | ✅ 描述里点明必填项 |
---
## ⚠️ 确信度标记(务必先读)
本文档所有字段名均来自**源码或真实响应样本**,不使用推测值。为便于区分,全文使用以下标记:
| 标记 | 含义 |
|---|---|
| ✅ **已确定** | 直接来自 `mis-mcp-server` 源码逻辑、下游实现源码,或真实接口响应样本,字段名与结构可信 |
| ⚠️ **透传** | MCP 层**不裁剪**,原样返回下游响应;字段结构以**下游 MIS/MBX 服务为准**,可能随下游变更 |
> 无法完全确证的少量细节**不散落在正文里**,统一收在 **§6.5 残留不确定项**。
> 写 prompt 前建议先扫一遍 **§6.4 高风险陷阱汇总**——那里是「照直觉写就会错」的地方。
> **给 AI 生成 prompt 的建议**:引用 ⚠️ 透传 字段时,prompt 里应写成「从返回的 `xxx` 字段读取」而非硬编码整个结构;
> 引用 ✅ 已确定 字段时可以放心直接取值。
---
## 目录
- [1. 工具总览](#1-工具总览)
- [2. 全局约定](#2-全局约定)
- [3. 工具详情](#3-工具详情)
- [3.1 `debuggingProjectQuery`](#31-debuggingprojectquery)
- [3.2 `queryProjectNameList`](#32-queryprojectnamelist)
- [3.3 `queryDriverListNamesByProject`](#33-querydriverlistnamesbyproject)
- [3.4 `queryDriverListVersion`](#34-querydriverlistversion)
- [3.5 `prepareTaskFile`](#35-preparetaskfile)
- [3.6 `generatePreloadUpdateLink`](#36-generatepreloadupdatelink)
- [3.7 `creatOrSendTask`](#37-creatorsendtask)
- [3.8 `queryTestUnitListByProjectName`](#38-querytestunitlistbyprojectname)
- [3.9 `queryTestPcByUuids`](#39-querytestpcbyuuids)
- [4. 典型工作流(编排剧本)](#4-典型工作流编排剧本)
- [5. 生成 SKILL 与 Prompt 的指引](#5-生成-skill-与-prompt-的指引)
- [6. 附录](#6-附录)
- [6.1 MCP 接入信息](#61-mcp-接入信息)
- [6.2 下游接口与白名单对照](#62-下游接口与白名单对照)
- [6.3 易混淆 / 已废弃工具](#63-易混淆--已废弃工具)
- [6.4 高风险陷阱汇总(写 prompt 前必读)](#64-高风险陷阱汇总写-prompt-前必读)
- [6.5 残留不确定项](#65-残留不确定项)
---
## 1. 工具总览
### 1.1 速查表
| # | MCP 工具名 | 所属服务 | 用途 | 必填参数 | 返回形态 |
|---|---|---|---|---|---|
| 1 | `debuggingProjectQuery` | `mis-mcp-tool-debugging` | 按项目名称/别名/五码查**项目基础信息** | 无(全部可选) | 分页信封 `{code,msg,total,rows[]}` ⚠️ |
| 2 | `queryProjectNameList` | `mis-mcp-tool-driver` | 取 MBX 侧**项目名称 + projectUuid** | 无(`creatorCode` 可选) | 数组 `[{name,projectUuid}]` ✅ |
| 3 | `queryDriverListNamesByProject` | `mis-mcp-tool-driver` | 按项目组/项目取**全部 Driver List Name** | `projectGroupUuid` 或 `projectUuid` | 数组 `[{driverListVersionUuid,driverListName}]` ✅ |
| 4 | `queryDriverListVersion` | `mis-mcp-tool-driver` | 取驱动列表版本的**包下载地址** | `driverListVersionUuid` | 下游对象 ⚠️(含 `packageFileUrl`) |
| 5 | `prepareTaskFile` | `mis-mcp-tool-driver` | 下载文件→重传到文件服务,换**任务下发可用的 fileUuid** | `fileUrl` | 对象 `{fileUuid,fileUrl,fileName,fileExtensionKey}` ✅ |
| 6 | `generatePreloadUpdateLink` | `mis-mcp-tool-vlab` | 生成 VLAB Preload 向导的**更新下载链接** | `project` | 对象(成功/失败两种结构)✅ |
| 7 | `creatOrSendTask` | `mis-mcp-tool-vlab` | **创建或下发测试任务** | `creatorCode`,`requestBodyJson` | 下游对象 ⚠️ / 纯文本提示 ✅ |
| 8 | `queryTestUnitListByProjectName` | `mis-mcp-tool-vlab` | 按项目名+五码查**机器列表** | `projectName`,`modelCode`,`ownerCode` | 下游列表 ⚠️ / 纯文本提示 ✅ |
| 9 | `queryTestPcByUuids` | `mis-mcp-tool-vlab` | 按 UUID 批量查**测试机在线状态** | `testUnitUuids` | 下游列表 ⚠️ |
> **参数必填标记来自源码**:`@ToolParam` 未写 `required = false` 即为**必填**。
### 1.2 数据依赖关系(谁喂谁)
这是生成 prompt 时最关键的一张图——**ID 都是一跳一跳传递的**:
```
① debuggingProjectQuery ──► projectName / projectUuid / modelCode
│
② queryProjectNameList ──────► projectUuid(MBX 侧)──┐
│
③ queryDriverListNamesByProject ◄─────────────────────┘
│ (需要 projectGroupUuid 或 projectUuid)
└──► driverListVersionUuid
│
④ queryDriverListVersion ◄──┘
└──► packageFileUrl
│
⑤ prepareTaskFile ◄─┘
└──► fileUuid
│
⑦ creatOrSendTask ◄──┘ (填入 requestBodyJson.model.children[].documentCopyDTOList[].fileUuid)
⑥ generatePreloadUpdateLink 独立链路,只需 project 名称(+ 可选 osVer)
⑧ queryTestUnitListByProjectName ──► testUnitUuid[]
│
⑨ queryTestPcByUuids ◄────────────────────┘ (查在线状态)
```
**关键 ID 传递表**:
| 上游工具 | 产出字段 | 下游工具 | 填入位置 |
|---|---|---|---|
| `queryDriverListNamesByProject` | `driverListVersionUuid` | `queryDriverListVersion` | 入参 `driverListVersionUuid` |
| `queryDriverListVersion` | `driverPackageVersionList[].packageFileUrl` | `prepareTaskFile` | 入参 `fileUrl` |
| `prepareTaskFile` | `fileUuid` | `creatOrSendTask` | `requestBodyJson.model.children[].documentCopyDTOList[].fileUuid` |
| `queryProjectNameList` | `projectUuid` | `queryDriverListNamesByProject` | 入参 `projectUuid` |
| `queryTestUnitListByProjectName` | `testUnitUuid` | `queryTestPcByUuids` | 入参 `testUnitUuids[]` |
### 1.3 语义说明:两个「项目查询」不重复(用户补充)
- `debuggingProjectQuery` —— 查的是 **SE 系统同步过来的 project** 信息;
- `queryProjectNameList` —— 查的是 **MBX 系统**的 project 信息;
- **两边的 project 的 `name` 值是对应的**,可互为参照。
> AI 写 prompt 时:要「项目基础信息」用 ①;要「能直接喂给 Driver 链路的 `projectUuid`」用 ②。
---
## 2. 全局约定
### 2.1 返回信封与三种裁剪行为
MCP 工具**全部返回字符串**(JSON 文本)。脱掉下游信封 `{code, msg, data}` 后,按模块有**三种**不同行为——写 prompt 时必须区分:
| 行为 | 工具 | 返回内容 |
|---|---|---|
| **A. 全量透传** | `debuggingProjectQuery` | 返回**整个信封** `{code,msg,total,rows[]}`,`rows[]` 内字段**不裁剪** ⚠️ |
| **B. 取 data(分页自动展平)** | `queryDriverListVersion`、`creatOrSendTask`、`queryTestUnitListByProjectName`、`queryTestPcByUuids` | 若 `data` 是对象且含 `records`,**只返回 `records` 数组**;否则返回 `data` 本身;`data` 为空返回 `"[]"` ⚠️ |
| **C. 取 data + 字段裁剪** | `queryProjectNameList`、`queryDriverListNamesByProject`、`prepareTaskFile`、`generatePreloadUpdateLink` | 只返回源码中显式挑出的字段 ✅ |
> **注意 B 类的空值表现**:`data` 为空时返回字符串 `"[]"`(**空数组**,不是空对象)。
### 2.2 分页参数命名不统一(易错点)
| 服务 | 页码参数 | 每页参数 | 默认值 |
|---|---|---|---|
| `mis-mcp-tool-debugging` | `pageNum` | `pageSize` | 1 / 10 |
| `mis-mcp-tool-driver` | `current` | `size` | 1 / 10(`queryProjectList*` / `queryDriverChidPage` / `queryDriverPackageList` / `queryWu*`)<br>1 / 5(`queryDriverListPage`) |
| `mis-mcp-tool-vlab` | `current` | `size` | 1 / 10 |
> **两个工具没有分页参数**(内部固定,调用方无需也无法指定):
> `queryProjectNameList`(固定第 1 页、每页 **100** 条)、`queryDriverListNamesByProject`(自动翻页取全量,每页 100 条)。
### 2.3 用户 ID 与鉴权
- **两种用户 ID 不能混用**:MCP 工具入参普遍收 **MIS 系统用户 ID**(如 `creatorCode`、`ownerCode`),
由服务内部通过 `MbxUserIdConverter` 转成 **MBX 用户 ID** 后传给下游(5 分钟本地缓存)。
- **转换失败有专用提示**:部分工具转换失败时返回**纯文本**而非 JSON,见 §2.4。
- **鉴权由 MCP 客户端透传**,调用方(LLM 侧)**不需要**在工具参数里传 token;
凭证走 MCP 请求头 `auth` / `clientid`,由 `MisAuthForestInterceptor` 注入下游。
### 2.4 非 JSON 返回(prompt 必须能识别)
以下情况返回的是**纯文本字符串**,不是 JSON——AI 解析时应先判断首字符:
| 工具 | 返回文本 | 触发条件 |
|---|---|---|
| `creatOrSendTask` | `请输入当前登录人信息` | `creatorCode` 为空,或 MIS→MBX 用户 ID 转换失败 |
| `queryTestUnitListByProjectName` | `登录人信息转换异常` | `ownerCode` 有值但转换失败 |
### 2.5 异常的处理方式
参数校验失败、下游业务失败时,工具**抛异常**(`IllegalArgumentException` / `RuntimeException`),
由 MCP 协议以错误形式返回,**不会**包装成 JSON。典型触发:
- `queryDriverListVersion`、`queryTestPcByUuids` 等:必填参数为空(如 `testUnitUuids` 空列表);
- 所有工具:下游返回非 JSON、下游业务码失败(错误信息取下游 `msg`)。
---
## 3. 工具详情
### 3.1 `debuggingProjectQuery`
**摘要**:根据项目名称、项目别名、项目五码查询项目基础信息,返回项目列表分页数据。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-debugging`(端口 18780,`STATELESS`) |
| Java 方法 | `ProjectMcpService.queryProjectList` |
| MCP 工具名 | `debuggingProjectQuery`(**源码中显式指定**,与 Java 方法名不同,调用时必须用这个名字) |
| 下游接口 | `GET {misApiBaseUrl}/debugging/project`(MIS 平台,网关白名单已放行) |
| 返回裁剪 | **A 类:全量透传**(`rows[]` 内 34 个字段全部返回,不裁剪)⚠️ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `projectName` | String | 否 | — | 项目名称 | `IdeaPad 5 Pro 16ARP8` |
| `projectAlias` | String | 否 | — | 项目别名 | — |
| `modelCode` | String | 否 | — | 项目五码 | `LT4EN` |
| `ppmQuery` | String | 否 | — | 项目负责人名称或参与人 | `san.zhang` |
| `mtCode` | String | 否 | — | 项目四码 | `81S3` |
| `pageSize` | Integer | 否 | `10` | 每页条数 | `10` |
| `pageNum` | Integer | 否 | `1` | 页码 | `1` |
**返回 JSON 结构** ✅(顶层 5 字段)/ ⚠️(透传,未裁剪)
```jsonc
{
"total": 0, // number 总条数
"rows": [ /* 见下表,Project 实体,34 个字段 */ ],
"code": 200, // number 成功码固定 200
"msg": "查询成功", // string
"extraData": null // 该接口路径下恒为 null
}
```
**`rows[]` 元素字段表**(实体 `com.lcfc.debugging.domain.Project`,**无任何 JSON 重命名注解**)
| 字段名 | 类型 | 说明 |
|---|---|---|
| `projectUuid` | Long → number/string | 主键。**类型不确定**:雪花 ID 超 2^53-1 时会被序列化成字符串,须按「可能是数字也可能是字符串」处理 |
| `idpProjectUuid` | String | idp 项目管理表主键 |
| `projectName` | String | Project Name 数据 |
| `projectCode` | String | Project code 数据 |
| `projectAlias` | String | 项目别名 |
| `lenovoProductName` | String | 联想产品名称 |
| `issueOwners` | Array\<Object\> | Issue Owner 列表,元素为 `{category, component, owner}` |
| `modelCode` | String | 五码信息(BOX Model Code) |
| `mtCode` | String | 四码信息 |
| `finCode` | String | 财务代码 |
| `bu` | String | BU 信息 |
| `developmentType` | String | Development Type |
| `generation` | String | Generation |
| `segment` | String | Segment |
| `pm` | String | PM |
| `ppm` | Array\<String\> | PPM 列表 |
| `pje` | Array\<String\> | PJE 列表 |
| `biosCode` | String | BIOS Code |
| `ddsTime` | String | 日期,格式固定 `yyyy-MM-dd` |
| `pkoTime` | String | 同上 |
| `evtStartTime` / `evtEndTime` | String | 同上 |
| `fvtStartTime` / `fvtEndTime` | String | 同上 |
| `sitStartTime` / `sitEndTime` | String | 同上 |
| `svtStartTime` / `svtEndTime` | String | 同上 |
| `sovpTime` / `ssTime` | String | 同上 |
| `actuaiEopTime` | String | 同上。**字段名拼写就是 `actuaiEopTime`**(非 `actual`),按原样使用 |
| `sort` | Integer | 排序号 |
| `delFlag` | String | 删除标志,查询恒定返回 `"0"` |
| `ppmQuery` | null | **恒为 null**(该字段只用于查询条件,不参与返回取值) |
**返回示例**(截取)
```json
{
"total": 1,
"rows": [
{
"projectUuid": "2049298006288687105",
"projectName": "IdeaPad 5 Pro 16ARP8",
"projectAlias": "LCP8",
"modelCode": "LT4EN",
"mtCode": "81S3",
"ppm": ["san.zhang"],
"pje": [],
"ddsTime": "2026-03-01",
"delFlag": "0",
"ppmQuery": null
}
],
"code": 200,
"msg": "查询成功",
"extraData": null
}
```
**注意事项**
- 这是**唯一一个返回「整个信封」**的工具(其余 debugging 工具会裁剪成 `{code,msg,total,rows[]}` 且过滤行内字段)。若 prompt 里要遍历数据,需先取 `rows`。
- `total` 是**总条数**,不是当前页条数。
- `projectUuid` 在别的工具里常以字符串形式出现,**做参数传递时按字符串处理最安全**。
- 查的是 **SE 系统同步过来的项目信息**,与 `queryProjectNameList` 的 MBX 侧数据来源不同,但 `name` 对应(见 §1.3)。
**关联工具**:`queryDriverListNamesByProject`(其 `projectUuid` 可来自本工具)、`queryProjectNameList`
---
### 3.2 `queryProjectNameList`
**摘要**:获取项目名称列表,返回 `name` 与 `projectUuid`。`creatorCode` 有值时只查该用户所涉及的项目。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-driver`(端口 18767,`STATELESS`) |
| Java 方法 | `DriverService.queryProjectNameList` |
| MCP 工具名 | `queryProjectNameList` |
| 下游接口 | `GET {misDriverBusinessBaseUrl}/project/mcpvlabpage`(MBX `mbv-service-business`) |
| 返回裁剪 | **C 类:取 data + 裁剪**,只保留 `name` / `projectUuid` ✅ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `creatorCode` | String | 否 | — | 当前登录人 **MIS 系统用户 ID**。有值 → 只查该用户涉及的项目 |
> **入参规则**(源码 `MbxUserIdConverter`):`creatorCode` 必须是**纯数字**的 MIS 用户 ID;
> 为空、非数字、或查不到映射时,工具**不会**把用户条件传给下游(即退化成「不带用户过滤」查询),**不报错**。
**返回 JSON 结构** ✅
```jsonc
[
{
"name": "string", // 项目名称:实际取自下游 portfolioProjectName
"projectUuid": "string" // 项目唯一标识,可直接喂给 queryDriverListNamesByProject
}
]
```
> **已核实**:下游 `ProjectPageInfo` **没有 `name` 字段**,所以源码里「`portfolioProjectName` 为空则回退 `name`」的兜底**永远不会触发**。
> 实际取值路径只有 `portfolioProjectName` 一条;该字段为空的行会被**整条丢弃**(不返回)。
> 因此 prompt 中应把 `name` 理解为「下游的项目名称(portfolioProjectName)」,不要去找别的名字来源。
**返回示例**
```json
[
{ "name": "IdeaPad 5 Pro 16ARP8", "projectUuid": "018cd84ba0a82b020410bb40a1d85ba5" },
{ "name": "Legion 5 15IRX10", "projectUuid": "000c798c09d537f4f25f5b29046aebd1" }
]
```
**注意事项**
- **本工具固定只取第 1 页、每页 100 条**(源码常量 `PROJECT_NAME_LIST_SIZE = 100`),即**最多返回 100 条项目**,且**没有分页参数**。
超过 100 条时**不会自动翻页**;需要按名称检索或取更多项目请用 `debuggingProjectQuery`。
(该常量原为 `2`,2026-09-22 修正为 `100`。)
- 返回**不含分页信息**,是纯数组。
- 两个字段都为空的下游记录会被过滤掉。
- 空结果返回 `"[]"`。
**关联工具**:`queryDriverListNamesByProject`(承接 `projectUuid`)、`debuggingProjectQuery`(项目基础信息)
---
### 3.3 `queryDriverListNamesByProject`
**摘要**:根据项目组唯一标识或项目唯一标识,查询对应的**全部** Driver List Name,返回 `driverListVersionUuid` 与 `driverListName` 集合。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-driver` |
| Java 方法 | `DriverService.queryDriverListNamesByProject` |
| MCP 工具名 | `queryDriverListNamesByProject` |
| 下游接口 | `GET {misDriverBaseUrl}/driverlist/mcpvlabpage`(内部自动翻页,每页 100 条直到取完) |
| 返回裁剪 | **C 类:裁剪并去重** ✅ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `projectGroupUuid` | String | 否 | — | 项目组唯一标识(与 `projectUuid` **至少给一个**) | `d5ac3039abf4c8302cccefc40f7056dd` |
| `projectUuid` | String | 否 | — | 项目唯一标识(与 `projectGroupUuid` **至少给一个**) | `018cd84ba0a82b020410bb40a1d85ba5` |
**返回 JSON 结构** ✅
```jsonc
[
{
"driverListVersionUuid": "string", // 驱动列表【版本】唯一标识 —— 给 queryDriverListVersion 用
"driverListName": "string" // 驱动列表名称:实际取自下游 driverListName
}
]
```
> **已核实**:源码写的是「优先取 `nameRemark`,为空则回退 `driverListName`」,但下游**分页接口的 SQL 根本没查 `name_remark` 列**,
> 因此 `nameRemark` 在这个链路上**恒为 null**,回退分支**必然生效** —— 返回值里的 `driverListName` 实际就是下游的 `driverListName`。
> (`nameRemark` 只在单查版本详情、即 §3.4 的返回里才有值。)对调用方而言:**只会拿到一个非空的 `driverListName`,直接用它做筛选即可**。
**返回示例**
```json
[
{ "driverListVersionUuid": "93b947167dad2e8956a70358742f70cc", "driverListName": "MyLNBGroup_Win10 21H2_V02" },
{ "driverListVersionUuid": "c95301ca9485a1bb2102989f91e5eaf9", "driverListName": "MyLNBGroup_Win10 21H2_V01_20260407" }
]
```
**注意事项**
- 返回的是**版本级**标识(`driverListVersionUuid`),**不是**驱动列表级标识;一个驱动列表有多个版本时会有多条。
- 结果已按 `driverListVersionUuid` **去重**;名称为空、UUID 为空的记录会被跳过。
- 工具内部会**自动翻页**(`size=100`)取全量,调用方**不需要**传分页参数,也没有分页参数。
- 返回**不含分页信息**,是纯数组;空结果返回 `"[]"`。
- 项目组/项目下驱动列表很多时,返回可能较长——prompt 里应引导模型**先按名称筛选**再取版本。
- ⚠️ **已知下游缺陷**:下游分页接口对「**一个版本都没有的空驱动列表**」会抛数组越界 → 返回 **500**。
出现「Driver 接口业务失败」类报错时,除了参数问题,也要考虑该分组下存在空驱动列表这一可能。
**关联工具**:`queryDriverListVersion`(承接 `driverListVersionUuid`)、`queryProjectNameList`(提供 `projectUuid`)
---
### 3.4 `queryDriverListVersion`
**摘要**:根据驱动列表唯一标识查询驱动列表版本信息,用于拿到**驱动包的下载地址**。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-driver` |
| Java 方法 | `DriverService.queryDriverListVersion` |
| MCP 工具名 | `queryDriverListVersion` |
| 下游接口 | `GET {misDriverBaseUrl}/listversion/mcpvlab/{driverListUuid}` |
| 返回裁剪 | **B 类:取 data(未做字段裁剪)** ⚠️ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `driverListVersionUuid` | String | **是** | — | 驱动列表版本唯一标识,来自 `queryDriverListNamesByProject` 的返回 | `93b947167dad2e8956a70358742f70cc` |
**返回 JSON 结构** ⚠️ **透传(未裁剪)**
MCP 层**只拆信封**,返回下游 `data` 的**完整内容**(`data` 为分页对象时取 `records`,为空时返回 `[]`)。
`data` 的结构是 `DriverListVersionVO`:
```jsonc
{
"driverListVersionUuid": "string",
"nameRemark": "string", // 本接口有值(与分页列表不同)
"driverListUuid": "string",
"driverListVersion": 0,
"status": null, // 下游未映射,恒 null
"driverListReleaseDate": "yyyy-MM-dd",
"creatorCode": "string",
"modifierCode": "string",
"createTime": "string",
"modifyTime": "string",
"activityStatusKey": "string",
"homesFlag": true,
"driverListName": "string",
"projectGroupUuid": "string",
"projectGroupName": "string",
"spmsProjectName": "string",
"driverListGmStatus": 0,
"driverListStatus": 0, // 0-临时 1-草稿 2-发布
"changeList": "string",
"remark": "string",
"comment": "string",
"osTypeKeyList": [0],
// ★★★ 目标产物在这里 ★★★
"driverPackageVersionList": [
{
"packageFileUrl": "★★ 驱动包下载地址 —— prepareTaskFile 的 fileUrl 入参",
"...": "DriverPackageVersionVO 其余字段"
}
],
"solidifiedDriverPackageVersionList": [ /* 结构同上,仅 driverListStatus==2(发布态)时有值 */ ],
"releaseContactUuidList": ["string"],
"releaseContactList": [ /* DriverContactVO */ ],
"driverPoContactList": [ /* DriverContactVO */ ],
"packageVersionNum": 0,
"bu": 0,
"logoNeeded": [0],
"platform": "string",
"baseIntelBkcVersion": "string",
"specialField": "string"
}
```
> ### ⚠️ 最容易踩的坑:`packageFileUrl` **不在顶层**
>
> MCP 实现**不裁剪字段**,`packageFileUrl` 也**不是顶层字段**——
> 它是嵌套元素 `DriverPackageVersionVO` 的字段,位于:
>
> - `driverPackageVersionList[].packageFileUrl`,或
> - `solidifiedDriverPackageVersionList[].packageFileUrl`(仅发布态 `driverListStatus == 2` 时有值)
>
> **prompt 必须写成「从 `driverPackageVersionList[].packageFileUrl` 取值」**,
> 若写成「取返回的 `packageFileUrl`」会取到 `undefined`。
> 建议优先读 `solidifiedDriverPackageVersionList`(发布态更稳定),为空再回退 `driverPackageVersionList`。
>
> ✅ **2026-09-22 已修正**:本工具的 `description` 原先写「返回 `packageFileUrl` 的下载地址即可」,
> 与实现不符,现已改为明确说明该字段的嵌套位置(见 `DriverService.queryDriverListVersion`)。
**注意事项**
- 入参 `driverListVersionUuid` 填的是**版本 UUID**(照抄 `queryDriverListNamesByProject` 的返回值)。
MCP 源码内部把它命名成 `driverListUuid` 只是**命名失误**,下游实际按版本 UUID 查询,不影响调用。
- 拿到的 `packageFileUrl` **不能直接**用于任务下发,必须再过 `prepareTaskFile`(见 §3.5)。
- 该 URL 形如 `http://<文件服务>/mbvClient/downloadFile?objectName=...&bucketName=driver`,**必须带 `objectName` 与 `bucketName`**。
- 传错成「驱动列表 UUID」时不会报错,而是 `data` 为 null → 返回 `[]`,需按空结果处理。
**关联工具**:`queryDriverListNamesByProject`(上游,提供 `driverListVersionUuid`)、`prepareTaskFile`(下游,消费 `packageFileUrl`)
---
### 3.5 `prepareTaskFile`
**摘要**:把「文件下载地址」对应的文件**重新上传到文件服务**,返回可用于测试任务下发的文件参数。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-driver` |
| Java 方法 | `DriverService.prepareTaskFile` |
| MCP 工具名 | `prepareTaskFile` |
| 下游接口 | ① `GET {misFileServiceBaseUrl}/mbvClient/downloadFile`(下载,`mbv-service-minio`)<br>② `POST {misFileServiceBaseUrl}/uploadFileSpecial`(上传到 `document` 桶) |
| 返回裁剪 | **C 类:裁剪** ✅ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `fileUrl` | String | **是** | — | 文件下载地址,来自 `queryDriverListVersion` 返回的 `packageFileUrl` | `http://10.159.41.130:8080/mbvClient/downloadFile?objectName=20260413/16/55/33/xxx.zip&bucketName=driver` |
> **`fileUrl` 必须带 `objectName` 与 `bucketName` 两个查询参数**,否则工具直接抛错(无法解析文件名/桶名)。
**返回 JSON 结构** ✅
```jsonc
{
"fileUuid": "string", // ★ 任务下发要用的文件唯一标识
"fileUrl": "string", // 上传后文件服务返回的访问地址
"fileName": "string", // 文件名(取自 objectName 最后一段)
"fileExtensionKey": 0 // 文件扩展名标识;类型不固定(可能是数字/字符串/null),按原样传递即可
}
```
**返回示例**
```json
{
"fileUuid": "8f2a1c9e4b7d4a1f9c3e5b6a7d8e9f01",
"fileUrl": "http://10.159.41.130:8080/mbvClient/downloadFile?objectName=document/20260922/xxx.zip&bucketName=document",
"fileName": "xxx.zip",
"fileExtensionKey": 3
}
```
**它在链路中的位置**(**这是本工具存在的唯一理由**)
```
queryDriverListVersion → packageFileUrl →【prepareTaskFile】→ fileUuid
→ creatOrSendTask 的
requestBodyJson.model.children[].documentCopyDTOList[].fileUuid
```
> 为什么不能直接把 `packageFileUrl` 填进任务下发?因为 `creatOrSendTask` 的 `documentCopyDTOList` **只认 `fileUuid`**,
> 而 driver 桶的文件不落文件信息表、没有 `file_uuid`。重传到 `document` 桶才能换到一个可用的 `fileUuid`。
> **因此这一步不可省略**,顺序也不能颠倒。
**注意事项**
- ⏱ **耗时较长**:驱动包可能有几百 MB,内部超时为 **10 分钟**。prompt 里应提示用户「这一步较慢,请稍候」。
- **不校验文件内容**,只做下载 + 上传;下载得到的是「HTTP 200 + 纯文本」形式的错误提示(如「文件不存在」)时会被拦截并报错。
- 返回的 `fileUrl` 是**上传后**的新地址(`document` 桶),与入参的 `packageFileUrl`(`driver` 桶)**不同**,不要混用。
**关联工具**:`queryDriverListVersion`(上游,提供 `fileUrl`)、`creatOrSendTask`(下游,消费 `fileUuid`)
---
### 3.6 `generatePreloadUpdateLink`
**摘要**:根据项目信息生成 VLAB Preload 向导页面的 **preload 更新下载链接**。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-vlab`(端口 18769,`STREAMABLE`,端点 `/mcp`) |
| Java 方法 | `PreloadService.generatePreloadUpdateLink` |
| MCP 工具名 | `generatePreloadUpdateLink` |
| 下游接口 | `mbv-service-preload`:`/preload/preloadNameList` → `/preload/init` → `/preload/select` → `/preload/getOtherList` → `/preload/preloadVersion` → `/aod` |
| 返回裁剪 | **C 类:自行组装** ✅ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `project` | String | **是** | — | 项目名称,**必须是 Preload 向导页面下拉选项中的值** | `IdeaPad 5 Pro 16ARP8` |
| `osVer` | String | 否 | 下拉列表**第一个**版本 | 操作系统版本,可用**页面展示名**(`description`)或**目录名**(`directory`) | `9.Win11` |
> 其余页面字段(Location、Preload VER、OS Type、Language、OS Edition、HDD Config、模块穿梭框)**均按页面默认值自动提交**,
> 调用方**无需也无法**指定。
**返回 JSON 结构** ✅ —— **成功与失败是两种不同结构,prompt 必须能区分**
**① 成功**
```jsonc
{
"downloadUrl": "string", // ★ 生成的 preload 更新下载链接
"project": "string", // 实际匹配到的项目名(回显下游下拉里的原值)
"osVer": "string", // 实际匹配到的 OS 版本展示名
"os": "string", // OS 目录名(directory)
"preloadVersion": "string", // 实际使用的 Preload VER
"locationName": "string" // 实际使用的 Location
}
```
**② 失败**(三种触发场景,`msg` 不同,附加字段也不同)
```jsonc
{
"success": false, // ★ 失败标志(注意:成功时【没有】success:true)
"msg": "string", // 失败原因
// 以下附加字段随场景变化:
"project": "string", // 回显入参
"osVer": "string", // 回显入参(可能为 null)
"os": "string", // 仅「未找到 Preload VER」场景
"preloadVersion": "string", // 仅「未返回下载地址」场景
"availableProjects": ["string"], // ★ 仅「Project 不在下拉选项中」场景
"availableOsVer": ["string"] // ★ 仅「OS VER 不在下拉选项中」场景
}
```
**失败场景对照表**
| `msg` | 触发条件 | 可用来自纠偏的字段 |
|---|---|---|
| `Project 不在 Preload 向导下拉选项中` | `project` 与下游下拉值**不匹配**(忽略大小写、去空格后仍不匹配) | `availableProjects` —— 全部合法项目名 |
| `OS VER 不在 Preload 向导下拉选项中` | `osVer` 既不是某版本的 `description` 也不是 `directory` | `availableOsVer` —— 全部合法 OS 版本名 |
| `未找到对应的 Preload VER` | 项目+OS 组合下 select 返回空 | `project` / `osVer` / `os` |
| `生成 Preload 更新链接失败,下游未返回下载地址` | 走到 `/aod` 但没拿到地址 | `project` / `osVer` / `preloadVersion` |
**返回示例**
```json
{
"downloadUrl": "http://mbxqas.lcfuturecenter.com/prod-api/preloadService/xxx/download?file=xxx.zip",
"project": "IdeaPad 5 Pro 16ARP8",
"osVer": "9.Win11",
"os": "Win11",
"preloadVersion": "PR9.0.0",
"locationName": "LCFC"
}
```
**注意事项**
- ⚠️ **判成功的正确写法**:检查是否**存在 `downloadUrl`**,或检查 `success === false`。
**不要**写 `success === true` —— 成功返回里**没有** `success` 字段。
- `project` / `osVer` 都是**按下游下拉值精确匹配**(忽略大小写与首尾空格),**不是模糊查询**。
传错时不会返回空数组,而是返回**失败对象 + 候选列表**——这是自纠偏的关键:
**prompt 应引导模型用 `availableProjects` / `availableOsVer` 重新选取后再重试一次,而不是反复用同一个错值重试。**
- `osVer` 不传时取下拉列表**第一个**版本,与页面默认行为一致。
- 该工具**会真实生成下载链接**(非只读查询),属于链路中副作用最强的一步。
**关联工具**:无上游依赖;项目名可参照 `debuggingProjectQuery` / `queryProjectNameList` 的 `name`(但**必须**用 Preload 页面下拉里的值)
---
### 3.7 `creatOrSendTask`
**摘要**:创建或下发测试任务。**本工作流中唯一的写操作**。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-vlab` |
| Java 方法 | `TaskService.creatOrSendTask` |
| MCP 工具名 | `creatOrSendTask`(**注意是 `creat` 不是 `create`**) |
| 下游接口 | `POST {misDispatcherBaseUrl}/mcpvlabcreatOrSendTask?fs={fs}&userId={userId}`,请求体为任务 JSON |
| 返回裁剪 | **B 类:取 data(未做字段裁剪)** ⚠️ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `creatorCode` | String | **是** | — | 当前登录人 **MIS 系统用户 ID**(纯数字)。服务内部转成 MBX `userId` 传给下游 |
| `requestBodyJson` | String | **是** | — | **任务请求体 JSON 字符串**。结构见下方“请求体”一节 |
| `fs` | Boolean | 否 | `false` | 随请求透传给下游的 `fs` 参数 |
### 请求体 `requestBodyJson` 结构 ✅(已核实下游 `DispatcherServiceImpl.commonCreateTask`)
> **`requestBodyJson` 必须是一个 JSON 字符串**(不是对象)。模型调用时需要把整个任务体**序列化成字符串**再作为参数传入。
> 下游用 Hutool 解析(非强类型 DTO),只有一个字段是硬性必填:**`other.type`**。
**顶层结构**
```jsonc
{
"base": { /* TestTask —— 任务基本信息 */ },
"other": { "type": 2 }, // ★ 必填!1=只保存 2=创建并下发
"rule": { /* TestTaskUnitBinding —— 选机器规则 */ },
"model": { /* TestModelNode —— 任务步骤树(模型视图时必填) */ },
"testTaskIssueTypeCode": 1, // 1=模型视图(默认) 2=用例视图
"testCaseAssociationVersionUuidList": [] // 仅用例视图(2)时必填
}
```
**`base` 常用字段**(`TestTask`)
| 字段 | 类型 | 说明 |
|---|---|---|
| `testTaskName` | String | 任务名称 |
| `testTaskTypeKey` | Integer | 1=测试任务,2=debug 任务 |
| `projectUuid` | String | 项目唯一标识 |
| `remark` | String | 备注 |
| `scheduleTime` | Date | 定时下发时间(**必须晚于当前时间**,否则报错) |
> 下发时会被下游**强制覆盖**的字段(传了也不生效):`testTaskCode`(重新生成)、
> `testModelUuid` / `testModelVersionUuid`、`ownerCode` / `creatorCode` / `operatorCode` / `modifierCode`(一律用 `userId` 覆盖)、
> `activityStatusKey`、`testTaskStatusKey`、`submitState`。
**`other` 字段**
| 字段 | 类型 | 说明 |
|---|---|---|
| `type` | Integer | **必填**。1=只保存,2=创建并下发。**为 null 会导致下游 NPE(500)** |
| `isClear` | Boolean | 是否清除当前执行任务 |
| `isDevice` | Boolean | — |
| `scheduleTime` | Date | 定时下发时间 |
**`rule` 常用字段**(`TestTaskUnitBinding`)——「选哪些机器」
| 字段 | 类型 | 说明 |
|---|---|---|
| `testTaskUnitBindingRuleKey` | Integer | 绑定规则:1=ssn 2=sku 3=mo 4=model 5=project |
| `bindingRulePriority` | Integer | 优先级 |
| `entityPrimaryKeyList` | Array\<String\> | ★ 选中的机器。**元素是 JSON 字符串,不是裸 UUID**,形如 `"{\"key\":\"<testUnitUuid>\",\"value\":\"<机器名>\"}"` |
**`model` 关键字段与文件挂载点**(`TestModelNode`,可递归)
```jsonc
{
"testModelUuid": "string",
"testModelVersionUuid": "string",
"testModelName": "string",
"nodeSequenceTypeKey": 1, // 1 串行 / 2 并行
"children": [
{
"testModelUuid": "string",
"testModelVersionUuid": "string",
"children": [],
// ★★★ 驱动包文件挂在这里 ★★★
"documentCopyDTOList": [
{
"fileUuid": "★ 填 prepareTaskFile 返回的 fileUuid",
"documentName": "string", // 可选
"documentVersionNo": "string" // 可选
}
]
}
]
}
```
> **`documentCopyDTOList` 里下游实际只用 `fileUuid`**(做判重与建文档映射),其余字段可选。
> 这与 §3.5 的链路说明一致。
**返回** ✅ / ⚠️
| 形态 | 内容 | 触发条件 |
|---|---|---|
| **纯文本** ✅ | `请输入当前登录人信息` | `creatorCode` 为空,**或** MIS→MBX 用户 ID 转换失败 |
| 异常 | `IllegalArgumentException: 任务请求体 requestBodyJson 不能为空` | `requestBodyJson` 为空 |
| **JSON** ⚠️ | 见下 | 正常调用 / 下游业务失败 |
**成功返回**(下游 `R.ok(statusMap, "任务下发已提交,正在生成中")`,MCP 取出 `data`)
```jsonc
{
"offLineTestUnit": "uuid1,uuid2,", // 离线机器 uuid,逗号拼接、末尾带逗号
"unWorkingTestUnit": "uuid3,", // 使用中机器 uuid,同上
"testTaskUuid": "string", // ★ 新建任务唯一标识
"testTaskCode": "string" // ★ 任务编号
}
```
**失败返回**(MCP 同样按 B 类处理:`data` 为 null 时返回 `[]`)
| 下游 `msg` | 含义 |
|---|---|
| `参数异常请检查` | ⚠️ 请求体为空。**下游这里返回的是 `code="0"`**,MCP 会当成成功路径处理,返回 `[]` —— 无法只靠 code 区分,需结合 `msg` |
| `任务定时下发时间需在当前时间之后,请重新设置!` | `scheduleTime` 早于当前时间 |
| `该任务含有禁用的用例关联版本,请修改重试!` | 用例关联版本被禁用 |
| `关联版本对应的绑定模型数据为空!` / `testCaseAssociationVersionUuid参数不得为空!` | 用例视图参数缺失 |
| `该任务含有不可用的原子模型,请修改重试!` | ⚠️ 此时下游 `code="26"`,`data` 是**列表** `[{deviceTypeKey, testUnitUuid, testUnitName}]`,MCP 会把该列表返回 |
**注意事项**
- ⚠️ **写操作**:会真实创建/下发任务,不可撤销。prompt 中应要求**先展示完整 `requestBodyJson` 给用户确认**再执行。
- `fileUuid` **必须**来自 `prepareTaskFile`,不能用 `packageFileUrl` 顶替(§3.5)。
- `creatorCode` 必须是**纯数字**的 MIS 用户 ID;非数字会走到「请输入当前登录人信息」分支,而不是报错——**prompt 需能识别这句纯文本并提示用户提供正确 ID**。
- `other.type` 忘了传 → 下游 NPE(500),这是最常见的构造错误。
- `fs=true` 会**跳过「机器未绑定设备类型」校验**并强制下发;默认 `false` 时该校验不过会返回 `code="26"`。
- 参数名与下游路径都是 `creat...`(少一个 e),拼错会找不到工具。
**关联工具**:`prepareTaskFile`(上游,提供 `fileUuid`)
---
### 3.8 `queryTestUnitListByProjectName`
**摘要**:根据项目名称、五码查询机器列表的数据,按列表分页显示。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-vlab` |
| Java 方法 | `UnitService.queryTestUnitListByProjectName` |
| MCP 工具名 | `queryTestUnitListByProjectName` |
| 下游接口 | `GET {misVlabBaseUrl}/testUnit/qv/mcpvlabqueryTestPcList` |
| 返回裁剪 | **B 类:取 data(未做字段裁剪)** ⚠️ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `projectName` | String | **是** | — | 项目名称 | `TNB Commercial OS Refresh-X_CS24` |
| `modelCode` | String | **是** | — | 五码 | `LT4EN` |
| `ownerCode` | String | **是** | — | 当前用户的 UUID(**MIS 用户 ID**,纯数字) | — |
| `current` | Long | 否 | `1` | 当前页码 | `1` |
| `size` | Long | 否 | `10` | 每页条数 | `10` |
> **参数名与下游字段名不一致**:工具入参叫 `modelCode`(五码),传给下游时字段名是 **`modelName`**。调用方只需按 `modelCode` 传值。
**返回** ✅ / ⚠️
| 形态 | 内容 | 触发条件 |
|---|---|---|
| **纯文本** ✅ | `登录人信息转换异常` | `ownerCode` 有值但 MIS→MBX 转换失败 |
| 异常 | `IllegalArgumentException: 项目名称 projectName 不能为空` | `projectName` 为空 |
| **JSON** ⚠️ | 下游 `data`(含 `records` 时只取 `records`;`data` 为空返回 `[]`) | 正常调用 |
**返回 JSON 结构** ⚠️ 透传(下游 `data` 是 MyBatis-Plus 分页对象,MCP 取出 `records`)
```jsonc
[
{
"testUnitUuid": "string", // ★ 测试机唯一标识 —— 给 queryTestPcByUuids 用
"testUnitName": "string", // 机器名称
"shippingSn": "string", // 出货流水号 / 机器 SSN
"onlineStatus": 2, // ★ 在线状态:1=离线 2=在线
"workingStatusKey": 2, // 机器状态:1=闲置中 2=使用中
"lockStatus": 0, // 锁定状态:0=未锁定 1=已锁定
"tokenStatus": 0, // 认领状态
"borrowStatus": 0, // 借用状态
"isStore": 0, // 是否收藏:0/1
"projectCode": "string", // 项目编号
"projectName": "string", // 项目名称
"projectPhase": "string", // 项目阶段
"programName": "string", // 项目集名称
"modelName": "string", // 五码
"groupName": "string", // 分组名称
"testUnitGroupUuid": "string", // 分组 uuid
"testUnitTypeKey": 0, // 测试机类型键 / 物料组
"matterDescription": "string", // 物料描述
"fgPn": "string", // SKU
"skuShortName": "string", // SKU 别名
"skuExtensionNo": "string", // SKU 扩展序号
"mbPn": "string", // 主板料号
"mbSn": "string", // 主板流水号
"fgSn": "string", // 整机流水号
"gerberVersion": "string", // 主板 Gerber 版本
"ipAddress": "string", // IP
"ipAddressBridge": "string", // 桥接 IP
"ownerCode": "string", // 机器管理员
"ownerName": "string", // 管理员名称
"userCode": 0, // 当前使用人编号
"userName": "string", // 当前使用人名称
"groupLeaderName": "string", // Smart FAI 组长姓名
"groupLeaderCode": "string", // Smart FAI 组长工号
"testUnitSource": "string", // 数据源:1=手工导入 2=开机注册
"comments": "string", // 备注
"gmtCreate": "yyyy-MM-dd HH:mm:ss", // 录入时间
"mbUuid": "string", // 主板 uuid
// 以下字段恒为 null(下游 SQL 未查出)
"mo": null,
"vncParam": null,
"lcfcUuid": null
}
]
```
**关键字段速查**
| 字段 | 取值 | 说明 |
|---|---|---|
| `testUnitUuid` | — | 传给 `queryTestPcByUuids` |
| `onlineStatus` | `1` 离线 / `2` 在线 | 在线状态 |
| `workingStatusKey` | `1` 闲置中 / `2` 使用中 | 机器状态 |
| `lockStatus` | `0` 未锁定 / `1` 已锁定 | 锁定状态 |
**注意事项**
- 三个入参(`projectName` / `modelCode` / `ownerCode`)在源码中**都是必填**。
- ⚠️ **`ownerCode` 不能留空**:MCP 允许它为空(不报错),但下游会直接返回
`未获取到用户信息`(`code="1"`)→ MCP 抛异常。**必须传纯数字的 MIS 用户 ID。**
- ⚠️ **`modelCode`(五码)实际不生效**:已核实下游该查询语句的 WHERE 子句里
**没有 `modelName` 过滤条件**,MCP 传过去的五码被**静默忽略**。
即实际过滤条件只有 `projectName`(+ 用户维度)。
**prompt 不要声称「按五码精确筛选」**;若确需按五码收窄,应在拿到结果后**在模型侧自行过滤** `modelName` 字段。
- 与已废弃的 `queryTestUnitList` 区分:**按项目查机器用本工具**(见 §6.3)。
**关联工具**:`queryTestPcByUuids`(下游,承接 `testUnitUuid`)、`debuggingProjectQuery`(提供 `modelCode` 五码)
---
### 3.9 `queryTestPcByUuids`
**摘要**:根据测试机 UUID 列表**批量**查询测试机在线状态信息。
| 项 | 值 |
|---|---|
| 所属服务 | `mis-mcp-tool-vlab` |
| Java 方法 | `TestUnitQvService.queryTestPcByUuids` |
| MCP 工具名 | `queryTestPcByUuids` |
| 下游接口 | `POST {misVlabBaseUrl}/testUnit/queryTestPcByUuids`,请求体 `{"testUnitUuids": [...]}` |
| 返回裁剪 | **B 类:取 data(未做字段裁剪)** ⚠️ |
**参数表**
| 参数名 | 类型 | 必填 | 默认 | 说明 | 示例 |
|---|---|---|---|---|---|
| `testUnitUuids` | Array\<String\> | **是** | — | 测试机 UUID **列表**(**批量传入**,不要循环单传) | `["0062c70e645c4d0a824d8b2c3134015d"]` |
**返回** ✅ / ⚠️
| 形态 | 内容 | 触发条件 |
|---|---|---|
| 异常 | `IllegalArgumentException: testUnitUuids 不能为空` | 入参为空列表或 null |
| **JSON** ⚠️ | 下游 `data` 本身就是一个**数组**(非分页) | 正常调用 |
**返回 JSON 结构** ⚠️ 透传
> 与 §3.8 不同,本接口的 `data` **直接就是数组**(不是分页对象),无需再取 `records`。
```jsonc
[
{
"testUnitUuid": "string", // 机器统一标识码
"testUnitName": "string", // 机器名称
"onlineStatusKey": 2, // ★★★ 在线状态:1=离线 2=在线
"workingStatusKey": 2, // 机器状态:1=空闲 2=使用中
"ownerCode": 0, // 所有者编号(数字)
"ownerName": "string", // 所有者名称
"userCode": 0, // 使用者编号(数字)
"sortField": null, // 继承自 SortEntity,非查询用途
"positiveOrReverse": null,
// ❌ 陷阱:这个字段名很像在线状态,但本接口恒为 null
"onlineStatus": null,
// 其余约 50 个字段(projectName / fgSn / lockStatus / gmtCreate …)也会出现,但恒为 null
"projectName": null,
"fgSn": null,
"lockStatus": null
}
]
```
> ### ⚠️ 最容易踩的坑:`onlineStatus` 是 null,要用 `onlineStatusKey`
>
> 下游 `Machines` 类里**同时存在**两个长得像在线状态的字段:
> - **`onlineStatusKey`** —— ✅ 本接口真正返回的在线状态(1 离线 / 2 在线)
> - `onlineStatus` —— ❌ 本接口的 SQL **没有查这一列**,恒为 `null`
>
> **prompt 里必须写 `onlineStatusKey`**。若写 `onlineStatus`,会拿到 `null` 并被误判成「离线/未知」。
**注意事项**
- **批量语义**:一次传入多个 UUID,比逐个调用高效——prompt 里应显式要求**合并成一次调用**。
- UUID 来源:`queryTestUnitListByProjectName` 返回的 `testUnitUuid`。
- 空数组会**直接抛异常**,不会返回空结果。
- 返回体很大(每台机器约 50+ 个恒 null 字段),**机器数量多时注意上下文占用**;
建议 prompt 里只提取 `testUnitUuid` / `testUnitName` / `onlineStatusKey` 三个字段。
**关联工具**:`queryTestUnitListByProjectName`(上游,提供 `testUnitUuids`)
---
## 4. 典型工作流(编排剧本)
> 每条链路都给出**步骤 → 工具 → 参数来源 → 产出**,可直接转成 SKILL 的调用顺序。
### 4.1 驱动包下发测试任务(最长链路,5 步)
| 步骤 | 工具 | 关键参数 | 取值来源 | 产出 |
|---|---|---|---|---|
| 1 | `queryProjectNameList` 或 `debuggingProjectQuery` | `projectName` / `creatorCode` | 用户输入 | `projectUuid` |
| 2 | `queryDriverListNamesByProject` | `projectUuid`(或 `projectGroupUuid`) | 步骤 1 | `driverListVersionUuid`、`driverListName` |
| 3 | `queryDriverListVersion` | `driverListVersionUuid` | 步骤 2 | `driverPackageVersionList[].packageFileUrl`(**非顶层字段**,见 §3.4) |
| 4 | `prepareTaskFile` | `fileUrl` = `packageFileUrl` | 步骤 3 | `fileUuid` ⏱ 耗时较长 |
| 5 | `creatOrSendTask` | `creatorCode`、`requestBodyJson`(含 `fileUuid`) | 步骤 4 + 用户输入 | 任务创建/下发结果 |
**决策点**(prompt 里必须交代清楚):
- 步骤 2 若匹配到**多个** `driverListName` → **列出让用户选**,不要自选。
- 步骤 4 耗时可能达数分钟 → 应提示用户。
- 步骤 5 是**写操作**(会真实创建/下发任务)→ 建议**先展示完整 `requestBodyJson` 给用户确认**再执行。
### 4.2 Preload 更新链接(单步 + 自纠偏)
| 步骤 | 工具 | 参数 | 产出 |
|---|---|---|---|
| 1 | `generatePreloadUpdateLink` | `project`(必填,页面下拉精确值)、`osVer`(可选) | `downloadUrl` |
**失败分支**:返回 `success: false` 时,用 `availableProjects` / `availableOsVer` 让用户确认后再**重试一次**(见 §3.6)。
### 4.3 项目 → 测试机 → 在线状态(3 步)
| 步骤 | 工具 | 关键参数 | 产出 |
|---|---|---|---|
| 1 | `debuggingProjectQuery` | `projectName` / `modelCode` | 项目信息(含五码 `modelCode`) |
| 2 | `queryTestUnitListByProjectName` | `projectName`、`modelCode`(五码)、`ownerCode` | 机器列表(含 `testUnitUuid`) |
| 3 | `queryTestPcByUuids` | `testUnitUuids` = 步骤 2 的 UUID 数组 | 在线状态 |
> 步骤 2 的三个参数在源码中**均为必填**(未标 `required = false`)。`ownerCode` 传 MIS 用户 ID。
---
## 5. 生成 SKILL 与 Prompt 的指引
> 本节把上文的结构化信息转成**可直接抄用的模板**。
### 5.1 推荐的 SKILL 结构
```markdown
---
name: se-driver-workflow # 建议按业务域命名,见下方 5.1.1
description: >
处理 SE 驱动的查询与测试任务下发。当用户提到「驱动列表」「Driver List」
「驱动包版本」「下发测试任务」「preload 更新链接」时使用。
覆盖 9 个 MCP 工具:项目查询、驱动列表查询、驱动包下载、文件准备、任务下发、
Preload 链接生成、测试机查询。
---
# 工具调用顺序(严格按此顺序,ID 逐跳传递)
1. queryProjectNameList / debuggingProjectQuery → 拿 projectUuid / 项目信息
2. queryDriverListNamesByProject → 拿 driverListVersionUuid
3. queryDriverListVersion → 拿 packageFileUrl
4. prepareTaskFile → 拿 fileUuid(耗时较长)
5. creatOrSendTask → 下发任务
# 详细参数与返回结构
见 `references/se工作流mcp工具API文档.md`(按需加载,不要一次性全读)
```
**5.1.1 SKILL 拆分建议**:按**链路**而非按工具拆,推荐 3 个:
| SKILL 名(建议) | 覆盖工具 | 触发场景 |
|---|---|---|
| `se-driver-workflow` | ①~⑤ + ⑦(`debuggingProjectQuery`/`queryProjectNameList`/`queryDriverListNamesByProject`/`queryDriverListVersion`/`prepareTaskFile`/`creatOrSendTask`) | 驱动查询与任务下发 |
| `se-preload-link` | ⑥ `generatePreloadUpdateLink` | 生成 Preload 更新链接 |
| `se-test-unit-query` | ⑧⑨ `queryTestUnitListByProjectName`/`queryTestPcByUuids` | 测试机列表与在线状态 |
### 5.2 工具 → 自然语言触发词
写 SKILL 的 `description` 时直接取用,能显著提高工具被正确选中的概率:
| 工具 | 用户可能说的话 |
|---|---|
| `debuggingProjectQuery` | 「查一下 XX 项目」「XX 项目的五码/四码/负责人」「项目别名是 XX 的项目」 |
| `queryProjectNameList` | 「有哪些项目」「我能看到哪些项目」「项目名和 projectUuid」 |
| `queryDriverListNamesByProject` | 「XX 项目下的 Driver List」「这个项目组有哪些驱动列表」「驱动列表版本」 |
| `queryDriverListVersion` | 「这个驱动列表的包在哪下载」「驱动包的下载地址」 |
| `prepareTaskFile` | 「准备一下这个文件」「把驱动包传上去」 |
| `generatePreloadUpdateLink` | 「生成 preload 更新链接」「Preload 更新包的下载地址」 |
| `creatOrSendTask` | 「下发测试任务」「创建测试任务」「跑一下这个驱动」 |
| `queryTestUnitListByProjectName` | 「XX 项目有哪些机器」「五码 XX 的测试机」 |
| `queryTestPcByUuids` | 「这几台机器在线吗」「机器在线状态」 |
### 5.3 编排 Prompt 模板
**模板 A:驱动包下发测试任务(最完整链路)**
```text
目标:把「{项目名}」项目下「{驱动列表名匹配词}」的驱动包,下发测试任务。
请严格按顺序执行,每步只用上一步的返回结果,不要跳步或猜 ID:
1. 调用 queryDriverListNamesByProject,参数 projectUuid = {projectUuid}(若只知道项目名,
先用 queryProjectNameList 拿 projectUuid)。
→ 从返回数组中选出名称匹配「{驱动列表名匹配词}」的那条,记下它的 driverListVersionUuid。
→ 如果匹配到多条,先列出来问我要哪一个,不要自己选。
2. 调用 queryDriverListVersion,参数 driverListVersionUuid = 上一步的值。
→ 从返回中取出 packageFileUrl。
3. 调用 prepareTaskFile,参数 fileUrl = 上一步的 packageFileUrl。
→ 这一步会下载并重新上传驱动包,可能耗时数分钟,请告知我在处理中。
→ 取出返回的 fileUuid。
4. 调用 creatOrSendTask:
- creatorCode = {当前登录人 MIS 用户 ID}
- requestBodyJson = 见下方模板,把 fileUuid 填入
model.children[].documentCopyDTOList[].fileUuid
- 执行前把完整 requestBodyJson 展示给我确认。
【重要】任何一步失败就停下来报告原因,不要用猜测的参数重试。
```
**模板 B:Preload 更新链接**
```text
帮我生成「{项目名}」的 preload 更新链接(OS VER 用 {9.Win11 / 不指定})。
调用 generatePreloadUpdateLink,参数 project = "{项目名}",osVer = "{osVer}"。
判断结果:
- 返回里有 downloadUrl → 成功,把链接给我。
- 返回里有 "success": false →
· 若带 availableProjects,从里面挑最接近的候选,把候选列表给我确认后再重试一次;
· 若带 availableOsVer,同理。
· 不要用同一个错值反复重试。
```
**模板 C:测试机在线状态**
```text
1. 调用 queryTestUnitListByProjectName:
projectName = "{项目名}",modelCode = "{五码}",ownerCode = "{当前登录人 MIS 用户 ID}"
→ 从返回里取出各机器的 testUnitUuid。
2. 调用 queryTestPcByUuids,testUnitUuids = 上一步的 UUID 数组(批量传入,不要一次一个)。
→ 汇总每台机器的在线状态给我。
```
### 5.4 反模式(写 prompt 时明确禁止)
| ❌ 不要这样写 | ✅ 应该这样写 | 原因 |
|---|---|---|
| 让模型「猜」或「编」`projectUuid` / `driverListVersionUuid` 等 UUID | 强制从上一个工具的返回中取值 | UUID 无法凭空生成,编造必然查不到 |
| 用 `queryProjectNameList` 取超过 100 条项目 | 用 `debuggingProjectQuery` 检索项目 | 前者单页最多 100 条且无分页参数(§3.2) |
| 把 `packageFileUrl` 直接填进 `creatOrSendTask` | 先过 `prepareTaskFile` 换成 `fileUuid` | 任务下发只认 `fileUuid`(§3.5) |
| 写「取返回的 `packageFileUrl`」 | 写「取 `driverPackageVersionList[].packageFileUrl`」 | 它不是顶层字段(§3.4) |
| 用 `onlineStatus` 判断测试机在线状态 | 用 `onlineStatusKey` | `onlineStatus` 恒为 null(§3.9) |
| 声称 `queryTestUnitListByProjectName` 按五码筛选 | 说明只按项目名筛选,五码需自行过滤 | 下游忽略 `modelName`(§3.8) |
| 让模型自行拼 `other.type` 等必填项 | 在 prompt 里给出完整请求体模板 | 漏传必填项会 500(§3.7) |
| 用 `success === true` 判断 Preload 成功 | 判断 `downloadUrl` 是否存在 / `success === false` | 成功返回里没有 `success` 字段(§3.6) |
| 对 `generatePreloadUpdateLink` 传模糊项目名 | 传 Preload 页面下拉里的**精确**值 | 该工具是精确匹配,不匹配会返回失败对象(§3.6) |
| 假设返回一定是 JSON | 先看首字符:`请`/`登` 开头是纯文本提示 | 两个工具会返回**纯文本**(§2.4) |
| 一次性读取整份 API 文档 | 按需加载对应工具小节 | 文档较长,全量加载浪费上下文 |
---
## 6. 附录
### 6.1 MCP 接入信息
| 服务 | 端口 | `protocol` | 配置来源 | 工具数(本工作流涉及) |
|---|---|---|---|---|
| `mis-mcp-tool-debugging` | 18780 | `STATELESS` | 仓库 `application.yml` | 1 |
| `mis-mcp-tool-driver` | 18767 | `STATELESS` | 仓库 `application.yml` | 4 |
| `mis-mcp-tool-vlab` | 18769 | `STREAMABLE`(`mcp-endpoint: /mcp`) | **Nacos**(仓库内无此配置) | 4 |
> ⚠️ **鉴权由 MCP 客户端透传**:调用方(LLM 侧)**不需要**把 token 作为工具参数传入。
> 凭证走 MCP 请求头 `auth` / `clientid`,由服务端 `MisAuthForestInterceptor` 注入下游。
> 排查「工具连不上」时,别只看仓库代码——`vlab` 的协议配置**不在代码里**,在 Nacos。
### 6.2 下游接口与白名单对照
下列路径**必须**存在于对应服务的 Nacos `security.oauth2.client.ignore-urls`(MBX 侧)或网关 `ignore.whites`(MIS 侧),
否则工具上线后必然 **401 / 403**。
| # | 工具 | 下游路径 | 下游服务 | 白名单位置 | 快照核对 |
|---|---|---|---|---|---|
| 1 | `debuggingProjectQuery` | `/debugging/project` | `mis-debugging` | **MIS 网关** `mis-gateway.yml` → `ignore.whites` | ✅ 已存在 |
| 2 | `queryProjectNameList` | `/project/mcpvlabpage` | `mbv-service-business` | `mbv-service-business-dev.yml` | ✅ 已存在 |
| 3 | `queryDriverListNamesByProject` | `/driverlist/mcpvlabpage` | `mbx-service-driver` | `mbx-service-driver-dev.yml` | ✅ 已存在 |
| 4 | `queryDriverListVersion` | `/listversion/mcpvlab/*` | `mbx-service-driver` | 同上 | ✅ 已存在 |
| 5 | `prepareTaskFile` | `/mbvClient/downloadFile`、`/uploadFileSpecial` | `mbv-service-minio` | `mbv-service-minio-dev.yml` | ✅ 已存在 |
| 6 | `generatePreloadUpdateLink` | `/preload/preloadNameList`、`/preload/init`、`/preload/select`、`/preload/getOtherList`、`/preload/preloadVersion`、`/aod` | `mbv-service-preload` | `mbv-service-preload-dev.yml` | ✅ 已存在(6 条齐全) |
| 7 | `creatOrSendTask` | `/mcpvlabcreatOrSendTask` | `mbv-service-dispatcher` | `mbv-service-dispatcher-dev.yml` | ✅ 已存在 |
| 8 | `queryTestUnitListByProjectName` | `/testUnit/qv/mcpvlabqueryTestPcList` | `mbv-service-business` | `mbv-service-business-dev.yml` | ✅ 已存在 |
| 9 | `queryTestPcByUuids` | `/testUnit/queryTestPcByUuids` | `mbv-service-business` | 同上 | ✅ 已存在 |
> **路径参数写 `*` 不写 `{}`**(如 `/listversion/mcpvlab/*`)。
> **本节结论基于本地 Nacos 快照**(`docs/nacos/`),快照是导出副本、**随时可能过期**,
> 上线前请以**远程 Nacos 实际值**为准。快照文件名是 `*-dev.yml` 但装的是 **qas** 环境的值。
### 6.3 易混淆 / 已废弃工具
| 工具 | 状态 | 说明 |
|---|---|---|
| `queryTestUnitList` | ⚠️ **已废弃**(源码 javadoc 明确标注「废弃」,但 `@Tool` 注解**未摘除**,仍会暴露给模型) | 参数多且语义宽泛,**不要**在新的 SKILL / prompt 里使用;按项目查机器请用 `queryTestUnitListByProjectName`,按 UUID 批量查用 `queryTestPcByUuids` |
| `debuggingProjectQuery` | 命名特殊 | 源码用 `@Tool(name = ...)` 显式指定,**Java 方法名是 `queryProjectList`**,两者不同名;调用时用 `debuggingProjectQuery` |
| `creatOrSendTask` | 拼写特殊 | 是 `creat` 不是 `create`,**必须原样使用** |
| `queryProjectNameList` vs `debuggingProjectQuery` | 数据源不同 | 前者查 MBX 侧,后者查 SE 同步侧;`name` 值对应(§1.3) |
### 6.4 高风险陷阱汇总(写 prompt 前必读)
> 以下每一条都来自**源码逐行核对**,都是「照直觉写就会错」的地方。
| # | 陷阱 | 正确做法 | 出处 |
|---|---|---|---|
| 1 | 以为 `queryDriverListVersion` 顶层有 `packageFileUrl` | 取 **`driverPackageVersionList[].packageFileUrl`**(或 `solidifiedDriverPackageVersionList[]`) | §3.4 |
| 2 | 用 `onlineStatus` 判断测试机在线状态 | 用 **`onlineStatusKey`**(`onlineStatus` 恒为 null) | §3.9 |
| 3 | 以为 `queryTestUnitListByProjectName` 会按五码筛选 | **`modelCode` 被下游静默忽略**;只按 `projectName` 过滤,需要五码请自行在结果里过滤 `modelName` | §3.8 |
| 4 | 给 `queryTestUnitListByProjectName` 传空 `ownerCode` | **必须传纯数字 MIS 用户 ID**,否则下游报「未获取到用户信息」 | §3.8 |
| 5 | 用 `success === true` 判断 Preload 成功 | 判断 **`downloadUrl` 是否存在** / `success === false`(成功返回里**没有** `success` 字段) | §3.6 |
| 6 | `creatOrSendTask` 漏传 `other.type` | **必须传**(`1` 只保存 / `2` 创建并下发),否则下游 NPE 500 | §3.7 |
| 7 | 把 `creatOrSendTask` 的空请求体当成失败 | 该场景下游返回 **`code="0"` + `msg="参数异常请检查"`**,是**假成功**,需结合 `msg` 判断 | §3.7 |
| 8 | 用 `queryProjectNameList` 拉取超过 100 条项目 | 它**单页最多 100 条且无分页**;项目检索用 `debuggingProjectQuery` | §3.2 |
| 9 | 假设返回值一定是 JSON | 两个工具会返回**纯文本**(`请输入当前登录人信息` / `登录人信息转换异常`) | §2.4 |
| 10 | 把 `packageFileUrl` 直接填进 `creatOrSendTask` | 必须先过 `prepareTaskFile` 换成 `fileUuid` | §3.5 |
| 11 | 把 `creatOrSendTask` 当只读查询 | 它是**写操作**,prompt 应先展示请求体让用户确认 | §3.7 |
### 6.5 残留不确定项
> 以下是本次核对**未能完全确证**的部分,不要在这些细节上做硬编码假设。
| # | 事项 | 状态 | 建议 |
|---|---|---|---|
| 1 | `debuggingProjectQuery` 返回的 `projectUuid` 是 number 还是 string | 下游类型为 `Long`,且全局注册了 `BigNumberSerializer`(值超 2^53-1 时输出**字符串**)。源码示例值 `2049298006288687105` 是 19 位雪花 ID → **实际应为字符串**;小 ID 历史数据可能为数字 | 统一**按字符串处理**(比较前归一) |
| 2 | MyBatis-Plus `Page` 序列化出的完整字段集 | 仅实锤 `records` / `total`(前端代码印证);`size`/`current`/`pages`/`orders` 等为框架常规字段,**未从 jar 逐项确认** | 只依赖 `records` / `total` |
| 3 | 下游抛 `RuntimeException`(如「生成任务编号失败」)经全局异常处理后的 JSON 结构 | **未确认** | 按 MCP 抛异常处理即可 |
| 4 | `queryTestUnitListByProjectName` 的 `machineListType` 分支 | MCP 不传该参数,走默认 SQL;另两条分支 SQL 未逐条核对 | 无需关注 |
| 5 | `debuggingProjectQuery` 的 `ppmQuery` 字段 | **已核实**:恒为 `null`(只作查询条件,不进结果映射) | 不要从返回值读它 |
| 6 | 值为 `null` 的字段是否会**整键消失** | **已核对**:下游无 `spring.jackson.*` 配置,MIS 共享配置 `application-common.yml` 未设 `default-property-inclusion` → **null 字段会原样输出** | 字段存在,判空即可 |
> **另需注意**:`mbv-service-test-unit` 模块里存在一份**同名**的 `/testUnit/queryTestPcByUuids` 实现,
> 但网关 `/business` 前缀落到的是 **`mbv-service-business`**,以本文档结论为准。
---
**文档结束** · 生成于 2026-09-22 · 基线 `mis-mcp-server@dev`