Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@
namespace Azure.Mcp.Core.Commands.Subscription;

public abstract class SubscriptionCommand<
[DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] TOptions, TResult>
[DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] TOptions, TResult>(ISubscriptionResolver subscriptionResolver)
: AuthenticatedCommand<TOptions, TResult> where TOptions : class, ISubscriptionOption
{
private readonly ISubscriptionResolver _subscriptionResolver;

protected SubscriptionCommand(ISubscriptionResolver subscriptionResolver)
{
_subscriptionResolver = subscriptionResolver;
}
private readonly ISubscriptionResolver _subscriptionResolver = subscriptionResolver;

public override void ValidateOptions(TOptions options, ValidationResult validationResult)
{
Expand Down
5 changes: 5 additions & 0 deletions core/Microsoft.Mcp.Core/src/Commands/BaseCommand`2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public virtual void PostBindOptions(TOptions options)
{
}

/// <summary>
/// Validates the options after they have been bound.
/// </summary>
/// <param name="options">The options to validate.</param>
/// <param name="validationResult">The validation result to populate.</param>
public virtual void ValidateOptions(TOptions options, ValidationResult validationResult)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,23 @@ public static bool TryGetValue<T>(this CommandResult commandResult, string optio
return GetValueOrDefaultImpl(commandResult, option);
}

/// <summary>
/// Special version for GetValueOrDefault for new option binding as the Option is immutable once created.
/// <para>
/// The name-based lookup was needed because the static Option would be re-created in RegisterOptions when changing
/// requiredness. CommandResult result retrieval uses the Option instance references as a Dictionary key. So,
/// changing requiredness in RegisterOptions and using the static Option in BindOptions would break silently and
/// necessitated the name based retrieval. That is no longer necessary with the new option binding approach and
/// this more performant approach should be used.
/// </para>
/// </summary>
/// <typeparam name="T">The type of the option value</typeparam>
/// <param name="commandResult">The command result</param>
/// <param name="option">The option</param>
/// <returns>The value of the option, or the default value if not found or not set</returns>
internal static T? GetValueOrDefaultWithoutName<T>(this CommandResult commandResult, Option<T> option)
=> GetValueOrDefaultImpl(commandResult, option);

private static T? GetValueOrDefaultImpl<T>(CommandResult commandResult, Option<T> option)
{
ArgumentNullException.ThrowIfNull(commandResult);
Expand Down
17 changes: 17 additions & 0 deletions core/Microsoft.Mcp.Core/src/Extensions/ParseResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ public static bool TryGetValue<T>(this ParseResult parseResult, string optionNam
public static T? GetValueOrDefault<T>(this ParseResult parseResult, Option<T> option)
=> GetValueOrDefault<T>(parseResult, option.Name);

/// <summary>
/// Special version for GetValueOrDefault for new option binding as the Option is immutable once created.
/// <para>
/// The name-based lookup was needed because the static Option would be re-created in RegisterOptions when changing
/// requiredness. ParseResult result retrieval uses the Option instance references as a Dictionary key. So,
/// changing requiredness in RegisterOptions and using the static Option in BindOptions would break silently and
/// necessitated the name based retrieval. That is no longer necessary with the new option binding approach and
/// this more performant approach should be used.
/// </para>
/// </summary>
/// <typeparam name="T">The type of the option value</typeparam>
/// <param name="parseResult">The parse result</param>
/// <param name="option">The option</param>
/// <returns>The value of the option, or the default value if not found or not set</returns>
internal static T? GetValueOrDefaultWithoutName<T>(this ParseResult parseResult, Option<T> option)
=> parseResult.CommandResult.GetValueOrDefaultWithoutName<T>(option);

/// <summary>
/// Gets the value of an option by name, returning default if not found or not set
/// </summary>
Expand Down
36 changes: 0 additions & 36 deletions core/Microsoft.Mcp.Core/src/Options/EnumOptionValidator.cs

This file was deleted.

10 changes: 10 additions & 0 deletions core/Microsoft.Mcp.Core/src/Options/OptionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,21 @@ public OptionAttribute(string description)
/// </summary>
public string? Name { get; init; }

/// <summary>
/// Additional CLI option names (without the "--" prefix).
/// </summary>
public string[]? Aliases { get; init; }

/// <summary>
/// A description of what the option controls. Used in help text and by AI agents.
/// </summary>
public string? Description { get; init; }

/// <summary>
/// A default value for the option when a value is not provided. Must match the property type being attributed.
/// </summary>
public object? DefaultValue { get; init; }

/// <summary>
/// Whether the option is hidden from help output.
/// </summary>
Expand Down
Loading