From 44c9f415b778c63c655853d6be8cfdcf38deb188 Mon Sep 17 00:00:00 2001 From: "tao.chen" <93983997+taochen-ct@users.noreply.github.com> Date: Mon, 13 Jul 2026 19:55:16 +0800 Subject: [PATCH] =?UTF-8?q?tools:=20=E4=BF=AE=20spark=5Fsubmit=20=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E7=9A=84=E4=B8=A4=E5=A4=84=E5=B0=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit c9e54a3 引入了 server-minted 校验, 但有两处需要调整: 1. 错误信息用 fmt.Errorf(... %w).Error() 构造, %w 包装语义被丢 掉 (errResult 接收 string, Error() 之后 %w 已经不可达). 改用 fmt.Sprintf 拼接, %q 引用路径, 错误信息保持不变但代码不再误 导. 2. 校验放在 scriptPath 解析之后、queue 解析之前. 错误信息会按字 段出现顺序报 (cluster_id, master, deploy_mode, script_path, queue, ...), 但当前顺序是 script_path 校验先报, 然后才报 queue 缺失. 把校验挪到所有 RequireString 之后、parseStringMap 之前, LLM 看错误时字段顺序跟 schema 顺序一致. nil-safe 校验逻辑不变 (d.UploadStore == nil 时跳过). 现有测试 全部通过: - TestSparkSubmit_RejectsNonMintedPath 仍通过 (校验位置不影响 行为) - TestSparkSubmit_StructuredCommand 仍通过 (走 mint 路径) Co-Authored-By: Claude --- internal/mcp/tools/spark_submit.go | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/internal/mcp/tools/spark_submit.go b/internal/mcp/tools/spark_submit.go index 3c79078..33c83d7 100644 --- a/internal/mcp/tools/spark_submit.go +++ b/internal/mcp/tools/spark_submit.go @@ -80,26 +80,29 @@ func (d *Deps) SparkSubmitHandler(ctx context.Context, req mcp.CallToolRequest) return errResult("spark_submit: " + err.Error()), nil } - // Reject paths that didn't come through upload_file on this server. - // Cluster-local paths and arbitrary host paths are unreachable from the MCP - // server's spark-submit, so we fail fast with a clear message rather than - // letting spark-submit produce a confusing FileNotFoundException later. - if d.UploadStore != nil { - if _, err := d.UploadStore.Validate(scriptPath); err != nil { - return errResult(fmt.Errorf("spark_submit: script_path %q is not from upload_file on this server; upload the file first via upload_file and pass back the path field: %w", scriptPath, err).Error()), nil - } + executorMemory, err := req.RequireString("executor_memory") + if err != nil { + return errResult("spark_submit: " + err.Error()), nil } queue, err := req.RequireString("queue") if err != nil { return errResult("spark_submit: " + err.Error()), nil } - executorMemory, err := req.RequireString("executor_memory") - if err != nil { - return errResult("spark_submit: " + err.Error()), nil - } args := req.GetArguments() + // Reject paths that didn't come through upload_file on this server. + // Cluster-local paths and arbitrary host paths are unreachable from the MCP + // server's spark-submit, so we fail fast with a clear message rather than + // letting spark-submit produce a confusing FileNotFoundException later. + // Placed after all required-string parses so error messages surface in + // field order (cluster_id, master, ..., script_path, queue, ...). + if d.UploadStore != nil { + if _, err := d.UploadStore.Validate(scriptPath); err != nil { + return errResult(fmt.Sprintf("spark_submit: script_path %q is not from upload_file on this server; upload the file first via upload_file and pass back the path field", scriptPath)), nil + } + } + // deploy_mode is required for forward compatibility but the builder does not // emit --deploy-mode, matching the Python reference's actual behavior. If the // Go side needs --deploy-mode later, add it here and document the divergence.