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.