using Newtonsoft.Json.Linq; using System; namespace MCPForUnity.Editor.Helpers { /// /// Unified parameter validation and extraction wrapper for MCP tools. /// Eliminates repetitive IsNullOrEmpty checks and provides consistent error messages. /// public class ToolParams { private readonly JObject _params; public ToolParams(JObject @params) { _params = @params ?? throw new ArgumentNullException(nameof(@params)); } /// /// Get required string parameter. Returns ErrorResponse if missing or empty. /// public Result GetRequired(string key, string errorMessage = null) { var value = GetString(key); if (string.IsNullOrEmpty(value)) { return Result.Error( errorMessage ?? $"'{key}' parameter is required." ); } return Result.Success(value); } /// /// Get optional string parameter with default value. /// Supports both snake_case and camelCase automatically. /// public string Get(string key, string defaultValue = null) { return GetString(key) ?? defaultValue; } /// /// Get optional int parameter. /// public int? GetInt(string key, int? defaultValue = null) { var str = GetString(key); if (string.IsNullOrEmpty(str)) return defaultValue; return int.TryParse(str, out var result) ? result : defaultValue; } /// /// Get optional bool parameter. /// Supports both snake_case and camelCase automatically. /// public bool GetBool(string key, bool defaultValue = false) { return ParamCoercion.CoerceBool(GetToken(key), defaultValue); } /// /// Get optional float parameter. /// public float? GetFloat(string key, float? defaultValue = null) { var str = GetString(key); if (string.IsNullOrEmpty(str)) return defaultValue; return float.TryParse(str, out var result) ? result : defaultValue; } /// /// Check if parameter exists (even if null). /// Supports both snake_case and camelCase automatically. /// public bool Has(string key) { return GetToken(key) != null; } /// /// Get raw JToken for complex types. /// Supports both snake_case and camelCase automatically. /// public JToken GetRaw(string key) { return GetToken(key); } /// /// Get raw JToken with snake_case/camelCase fallback. /// private JToken GetToken(string key) { // Try exact match first var token = _params[key]; if (token != null) return token; // Try snake_case if camelCase was provided var snakeKey = ToSnakeCase(key); if (snakeKey != key) { token = _params[snakeKey]; if (token != null) return token; } // Try camelCase if snake_case was provided var camelKey = ToCamelCase(key); if (camelKey != key) { token = _params[camelKey]; } return token; } private string GetString(string key) { // Try exact match first var value = _params[key]?.ToString(); if (value != null) return value; // Try snake_case if camelCase was provided var snakeKey = ToSnakeCase(key); if (snakeKey != key) { value = _params[snakeKey]?.ToString(); if (value != null) return value; } // Try camelCase if snake_case was provided var camelKey = ToCamelCase(key); if (camelKey != key) { value = _params[camelKey]?.ToString(); } return value; } private static string ToSnakeCase(string str) => StringCaseUtility.ToSnakeCase(str); private static string ToCamelCase(string str) => StringCaseUtility.ToCamelCase(str); } /// /// Result type for operations that can fail with an error message. /// public class Result { public bool IsSuccess { get; } public T Value { get; } public string ErrorMessage { get; } private Result(bool isSuccess, T value, string errorMessage) { IsSuccess = isSuccess; Value = value; ErrorMessage = errorMessage; } public static Result Success(T value) => new Result(true, value, null); public static Result Error(string errorMessage) => new Result(false, default, errorMessage); /// /// Get value or return ErrorResponse. /// public object GetOrError(out T value) { if (IsSuccess) { value = Value; return null; } value = default; return new ErrorResponse(ErrorMessage); } } }