mes-mcp 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -75,6 +75,8 @@ npm run dev
|
|
|
75
75
|
写入类动作通过 `confirm_required` 或 `commit` 执行时需要幂等键。调用方没有显式传入时,`mes-mcp` 会为当前工具调用生成一条集成幂等键;需要跨重试严格复用同一幂等键的批处理场景,仍建议调用方显式传入 `idempotencyKey`。
|
|
76
76
|
|
|
77
77
|
- `mes_api.read`:按当前 MES 账号权限读取普通业务接口,例如 `/sale-order/list`、`/material/detail`。后端只放行只读类接口,写入动作必须使用动态业务动作;读取调用会在 MES AI 调用日志里记录路径、请求摘要和结果摘要。
|
|
78
|
+
- `mes://agent/context`:MES Agent 通用操作边界、工具顺序和安全规则。
|
|
79
|
+
- `mes://flows/sale-delivery`:销售出库上下文资源,只描述读取顺序和阻断处理;可出库状态、库存和质量判断仍以后端接口返回为准。
|
|
78
80
|
|
|
79
81
|
写入类工具支持 `executionMode`:
|
|
80
82
|
|
|
@@ -15,10 +15,11 @@ export function registerMesPrompts(server) {
|
|
|
15
15
|
text: [
|
|
16
16
|
"你是 MES 业务助手,必须按当前账号权限和工具返回结果执行。",
|
|
17
17
|
"不要猜测客户、物料、BOM、工艺路线、仓库等关键主数据;缺失时先查询或要求用户确认。",
|
|
18
|
-
"动作目录有数百个动作。发现动作时用 mes_action.list,把你当前要做的事用一句自然语言意图传给 keyword(例如「销售单转生产计划」「采购入库」「报工」),它返回按相关性排序的 top-K 动作;再用 mes_action.detail
|
|
18
|
+
"动作目录有数百个动作。发现动作时用 mes_action.list,把你当前要做的事用一句自然语言意图传给 keyword(例如「销售单转生产计划」「采购入库」「报工」),它返回按相关性排序的 top-K 动作;再用 mes_action.detail 查看字段。遇到前置步骤、字段归属或业务口径不清楚时,先用 mes_manual.search 或 mes_workflow.detail 查后端手册索引,最后用 mes_action.execute 执行。不要不带意图地翻页或猜路径,也不要依赖工具列表里必须存在 mes.<动作编码>。",
|
|
19
19
|
"mes_action.execute 返回的是执行信封,真实业务返回在 data 字段;confirm_required 产生的 invocationId 必须由同一公司/租户下有权限的账号审批。",
|
|
20
20
|
"mes_api.read 只用于普通业务只读接口,pageSize 最大 100;如果返回 _mcpWarnings 或提示需要动态动作,请按提示调整。",
|
|
21
|
-
"
|
|
21
|
+
"销售到出库的流程也走动态动作:先查客户和物料,再创建销售单、处理审批、确认销售单、转生产计划、排产或生成工单、报工、质检、生产入库/库存确认、发货出库。",
|
|
22
|
+
"涉及销售出库时先读取 `mes://flows/sale-delivery`。不要从工单状态或销售订单状态自行推断可出库;必须先查询后端销售订单行、剩余可出库数量、目标仓库存证据和相关入库事实。有 blockers 时停止写入并向用户说明原因。",
|
|
22
23
|
"库存盘点差异优先使用 stock.stock_count.create/update/start/submit/approve 盘点单流程;stock.batch_adjust 只适合非批次物料的简化批量差异调整,批次追踪物料请使用 stock.adjust 并指定 batchNo。",
|
|
23
24
|
"写入类动作默认先使用 confirm_required 或 preview;preview 不写入,confirm_required 生成待确认记录,commit 只有凭证允许时才真实提交。",
|
|
24
25
|
context ? `当前上下文:${context}` : "",
|
|
@@ -37,10 +37,11 @@ export function registerMesResources(server, client) {
|
|
|
37
37
|
"## 工具使用顺序",
|
|
38
38
|
"",
|
|
39
39
|
"1. 使用 `mes_action.list` 或 `mes://agent/actions` 发现当前凭证和账号权限允许的动作。",
|
|
40
|
-
"2. 使用 `mes_action.detail` 查看目标动作的路径、权限、DTO
|
|
41
|
-
"3.
|
|
42
|
-
"4.
|
|
43
|
-
"5.
|
|
40
|
+
"2. 使用 `mes_action.detail` 查看目标动作的路径、权限、DTO 名称、输入 schema、字段归属和推荐工作流提示。",
|
|
41
|
+
"3. 如果业务链路或字段归属不清楚,使用 `mes_manual.search` / `mes_manual.get` / `mes_workflow.detail` 查询后端提供的 AI 操作手册索引。",
|
|
42
|
+
"4. 只读查询使用 `mes_api.read` 调用普通业务只读 POST 接口。",
|
|
43
|
+
"5. 写入、确认、下达、报工、质检、出入库等动作使用 `mes_action.execute` 或可选的 `mes.<动作编码>`。",
|
|
44
|
+
"6. `MES_REGISTER_DYNAMIC_TOOLS=false` 是默认推荐配置;此时工具列表包含 `mes_api.read`、`mes_action.list/detail/execute`、`mes_manual.search/get`、`mes_workflow.detail` 等基础工具。只有客户端必须直观看到 `mes.<动作编码>` 时才开启动态工具展开。",
|
|
44
45
|
"",
|
|
45
46
|
"## 写入规则",
|
|
46
47
|
"",
|
|
@@ -63,6 +64,14 @@ export function registerMesResources(server, client) {
|
|
|
63
64
|
"- `stock.out` 只用于无来源直接出库,类型限定为 `out_scrap` 或 `out_other`;销售发货不要绕过销售出库单。",
|
|
64
65
|
"- `stock.batch_adjust` 只适合非批次物料的简化批量差异调整;批次追踪物料请使用 `stock.adjust` 并传 `batchNo`。",
|
|
65
66
|
"",
|
|
67
|
+
"## 销售出库防误操作",
|
|
68
|
+
"",
|
|
69
|
+
"- 销售出库必须以后端返回的销售订单、订单行、库存和动作详情为准,不能从工单状态自行推断可出库。",
|
|
70
|
+
"- 用户说“已完工 / finished”时,先读取 `work_order.list` 的动作详情或接口 schema 确认合法状态枚举;不要把自然语言状态原样传给接口。",
|
|
71
|
+
"- 工单完工只代表生产执行状态,不代表成品已经确认入库;出库前必须查询后端库存或后端候选/预检接口。",
|
|
72
|
+
"- 没有明确的销售订单行、客户、出库仓库、剩余可出库数量和后端库存证据时,不要创建或确认销售出库单。",
|
|
73
|
+
"- 如果库存不足、缺少生产入库单、缺少客户或状态不允许,停止写入动作并向用户说明阻断原因和下一步查询建议。",
|
|
74
|
+
"",
|
|
66
75
|
"## 防误连",
|
|
67
76
|
"",
|
|
68
77
|
"- MCP 启动时会在 stderr 打印 MES 地址、Token 用户名、apiKeyId、agentClientId 和动态工具状态。",
|
|
@@ -77,4 +86,49 @@ export function registerMesResources(server, client) {
|
|
|
77
86
|
},
|
|
78
87
|
],
|
|
79
88
|
}));
|
|
89
|
+
server.registerResource("mes_sale_delivery_flow", "mes://flows/sale-delivery", {
|
|
90
|
+
title: "MES Sales Delivery Flow",
|
|
91
|
+
description: "销售出库 AI 执行上下文:说明读取顺序、后端事实来源和阻断处理,避免 AI 从工单或销售单状态自行推断可出库。",
|
|
92
|
+
mimeType: "text/markdown",
|
|
93
|
+
}, async (uri) => ({
|
|
94
|
+
contents: [
|
|
95
|
+
{
|
|
96
|
+
uri: uri.href,
|
|
97
|
+
mimeType: "text/markdown",
|
|
98
|
+
text: [
|
|
99
|
+
"# MES Sales Delivery Flow",
|
|
100
|
+
"",
|
|
101
|
+
"本资源只描述 AI 应如何读取后端事实,不承载 MES 业务规则。状态、权限、库存、质量、可执行性和审计均以后端接口返回为准。",
|
|
102
|
+
"",
|
|
103
|
+
"## 核心原则",
|
|
104
|
+
"",
|
|
105
|
+
"- 不要把“工单已完工”当成“可销售出库”。工单、生产入库单、库存和销售出库单是不同业务事实。",
|
|
106
|
+
"- 不要在 MCP 端维护可出库状态白名单、库存扣减规则或质量规则。",
|
|
107
|
+
"- 写入前必须用后端只读接口或动作详情取得当前事实;事实不完整时停止写入并说明缺口。",
|
|
108
|
+
"",
|
|
109
|
+
"## 推荐读取顺序",
|
|
110
|
+
"",
|
|
111
|
+
"1. 用 `mes_action.list` 搜索“销售出库 / 创建出库单 / 确认出库单”,再用 `mes_action.detail` 读取 `sale_delivery.create` 和 `sale_delivery.confirm` 的最新 schema。",
|
|
112
|
+
"2. 用 `mes_api.read` 查询 `/sale-order/list` 或 `/sale-order/detail`,确认销售订单、客户、订单行和后端返回的剩余可出库信息。",
|
|
113
|
+
"3. 对每个订单行,用 `mes_api.read` 查询 `/stock/list`,按物料和候选出库仓库读取后端库存行;没有库存证据时不要继续确认出库。",
|
|
114
|
+
"4. 如果用户从工单切入,先查询 `/work-order/list` 或 `/work-order/detail` 只确认工单事实,再查询 `/production-receipt/list`、`/production-receipt/output-buffer/list` 和 `/stock/list` 确认是否已经形成可用库存。",
|
|
115
|
+
"5. 只有后端事实齐全且没有阻断时,才用 `mes_action.execute` 执行 `sale_delivery.create`;确认出库使用 `sale_delivery.confirm`,最终库存扣减仍由后端复验。",
|
|
116
|
+
"",
|
|
117
|
+
"## 阻断时的回答",
|
|
118
|
+
"",
|
|
119
|
+
"- 库存不足:不要创建或确认出库单;说明目标仓库库存不足,并建议查询生产入库单、生产输出暂存、调拨或采购入库。",
|
|
120
|
+
"- 没有销售订单行:不要用工单直接拼出库单;要求用户指定销售订单或先查询待出库销售订单。",
|
|
121
|
+
"- 状态或字段不合法:引用后端错误或 schema 合法枚举,改用后端合法值重新查询。",
|
|
122
|
+
"- 缺客户、仓库、批次、库位等关键事实:先查询或要求用户确认,不要伪造默认值。",
|
|
123
|
+
"",
|
|
124
|
+
"## 写入模式",
|
|
125
|
+
"",
|
|
126
|
+
"- 优先使用 `preview` 或 `confirm_required`。",
|
|
127
|
+
"- `preview` 只校验工具调用形态,不代表业务已成功写入。",
|
|
128
|
+
"- `confirm_required` 生成待确认调用,最终是否执行仍由同公司有权限账号确认。",
|
|
129
|
+
"- `commit` 只有当前凭证允许且用户明确要求时才使用。",
|
|
130
|
+
].join("\n"),
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
}));
|
|
80
134
|
}
|
|
@@ -268,7 +268,7 @@ function registerGenericActionTools(server, client, searchService) {
|
|
|
268
268
|
});
|
|
269
269
|
server.registerTool("mes_action.detail", {
|
|
270
270
|
title: "Get MES business action detail",
|
|
271
|
-
description: "查询单个 MES 页面业务动作的路径、权限、DTO
|
|
271
|
+
description: "查询单个 MES 页面业务动作的路径、权限、DTO 名称、输入 schema,以及后端提供的手册引用、字段归属和推荐工作流提示。",
|
|
272
272
|
inputSchema: z.object({
|
|
273
273
|
actionCode: z.string().min(1),
|
|
274
274
|
}),
|
|
@@ -288,6 +288,100 @@ function registerGenericActionTools(server, client, searchService) {
|
|
|
288
288
|
return formatToolResult(result);
|
|
289
289
|
});
|
|
290
290
|
});
|
|
291
|
+
server.registerTool("mes_manual.search", {
|
|
292
|
+
title: "Search MES operation manual",
|
|
293
|
+
description: "检索后端提供的 MES AI 操作手册索引,用于补充字段归属、前置动作、推荐流程和常见误用。适合在只看 action schema 不确定业务链路时调用。",
|
|
294
|
+
inputSchema: z
|
|
295
|
+
.object({
|
|
296
|
+
query: z.string().optional().describe("自然语言查询词"),
|
|
297
|
+
keyword: z.string().optional().describe("兼容字段:自然语言查询词"),
|
|
298
|
+
module: z.string().optional().describe("业务模块,如 schedule"),
|
|
299
|
+
actionCode: z
|
|
300
|
+
.string()
|
|
301
|
+
.optional()
|
|
302
|
+
.describe("相关动作编码,如 schedule.plan.auto"),
|
|
303
|
+
field: z
|
|
304
|
+
.string()
|
|
305
|
+
.optional()
|
|
306
|
+
.describe("字段名或字段归属,如 planStartDate"),
|
|
307
|
+
page: z.number().int().positive().optional(),
|
|
308
|
+
pageSize: z
|
|
309
|
+
.number()
|
|
310
|
+
.int()
|
|
311
|
+
.positive()
|
|
312
|
+
.max(MAX_MES_PAGE_SIZE)
|
|
313
|
+
.optional(),
|
|
314
|
+
})
|
|
315
|
+
.passthrough(),
|
|
316
|
+
annotations: {
|
|
317
|
+
readOnlyHint: true,
|
|
318
|
+
destructiveHint: false,
|
|
319
|
+
idempotentHint: true,
|
|
320
|
+
},
|
|
321
|
+
}, async (args) => {
|
|
322
|
+
return runTool({ toolName: "mes_manual.search" }, async () => {
|
|
323
|
+
const parsed = z
|
|
324
|
+
.object({
|
|
325
|
+
query: z.string().optional(),
|
|
326
|
+
keyword: z.string().optional(),
|
|
327
|
+
module: z.string().optional(),
|
|
328
|
+
actionCode: z.string().optional(),
|
|
329
|
+
field: z.string().optional(),
|
|
330
|
+
page: z.number().int().positive().optional(),
|
|
331
|
+
pageSize: z.number().int().positive().optional(),
|
|
332
|
+
})
|
|
333
|
+
.passthrough()
|
|
334
|
+
.parse(args ?? {});
|
|
335
|
+
const warnings = [];
|
|
336
|
+
const payload = normalizePageSize(parsed, warnings);
|
|
337
|
+
const result = await client.post("/integration/agent/manual/search", payload);
|
|
338
|
+
return formatToolResult(result, warnings);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
server.registerTool("mes_manual.get", {
|
|
342
|
+
title: "Get MES operation manual section",
|
|
343
|
+
description: "按手册章节 ID 获取后端提供的 MES AI 操作手册详情,返回动作链、字段归属、步骤和常见误用。",
|
|
344
|
+
inputSchema: z.object({
|
|
345
|
+
id: z.string().min(1).describe("手册章节 ID"),
|
|
346
|
+
}),
|
|
347
|
+
annotations: {
|
|
348
|
+
readOnlyHint: true,
|
|
349
|
+
destructiveHint: false,
|
|
350
|
+
idempotentHint: true,
|
|
351
|
+
},
|
|
352
|
+
}, async (args) => {
|
|
353
|
+
return runTool({ toolName: "mes_manual.get" }, async () => {
|
|
354
|
+
const parsed = z
|
|
355
|
+
.object({
|
|
356
|
+
id: z.string().min(1),
|
|
357
|
+
})
|
|
358
|
+
.parse(args ?? {});
|
|
359
|
+
const result = await client.post("/integration/agent/manual/detail", parsed);
|
|
360
|
+
return formatToolResult(result);
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
server.registerTool("mes_workflow.detail", {
|
|
364
|
+
title: "Get MES recommended workflow",
|
|
365
|
+
description: "按工作流 ID 获取后端推荐的 MES 业务动作链。用于需要多个动作配合完成的场景,例如先更新生产计划开始日期,再从生产计划排产。",
|
|
366
|
+
inputSchema: z.object({
|
|
367
|
+
id: z.string().min(1).describe("业务工作流 ID"),
|
|
368
|
+
}),
|
|
369
|
+
annotations: {
|
|
370
|
+
readOnlyHint: true,
|
|
371
|
+
destructiveHint: false,
|
|
372
|
+
idempotentHint: true,
|
|
373
|
+
},
|
|
374
|
+
}, async (args) => {
|
|
375
|
+
return runTool({ toolName: "mes_workflow.detail" }, async () => {
|
|
376
|
+
const parsed = z
|
|
377
|
+
.object({
|
|
378
|
+
id: z.string().min(1),
|
|
379
|
+
})
|
|
380
|
+
.parse(args ?? {});
|
|
381
|
+
const result = await client.post("/integration/agent/workflows/detail", parsed);
|
|
382
|
+
return formatToolResult(result);
|
|
383
|
+
});
|
|
384
|
+
});
|
|
291
385
|
server.registerTool("mes_action.execute", {
|
|
292
386
|
title: "Execute MES business action",
|
|
293
387
|
description: "执行一个由 mes_action.list 发现的 MES 页面业务动作。后端复用页面 Controller、DTO、权限、租户、状态机和调用日志。返回体是执行信封:真实业务结果在 data 字段;confirm_required 返回待确认 invocationId,必须由同一公司/租户下有权限的账号审批。",
|