public sealed class IndexDescribeCommand()

in src/Commands/Search/Index/IndexDescribeCommand.cs [17:137]


public sealed class IndexDescribeCommand(ILogger<IndexDescribeCommand> logger) : GlobalCommand<IndexDescribeArguments>()
{
    private readonly ILogger<IndexDescribeCommand> _logger = logger;
    private readonly Option<string> _serviceOption = ArgumentDefinitions.Search.Service.ToOption();
    private readonly Option<string> _indexOption = ArgumentDefinitions.Search.Index.ToOption();

    protected override string GetCommandName() => "describe";

    protected override string GetCommandDescription() =>
        """
        Get the full definition of an Azure AI Search index. Returns the complete index configuration including
        fields, analyzers, suggesters, scoring profiles, and other settings.

        Required arguments:
        - service-name: The name of the Azure AI Search service
        - index-name: The name of the search index to retrieve
        """;

    protected override void RegisterOptions(Command command)
    {
        base.RegisterOptions(command);
        command.AddOption(_serviceOption);
        command.AddOption(_indexOption);
    }

    protected override void RegisterArguments()
    {
        base.RegisterArguments();
        AddArgument(CreateServiceArgument());
        AddArgument(CreateIndexArgument());
    }

    protected override IndexDescribeArguments BindArguments(ParseResult parseResult)
    {
        var args = base.BindArguments(parseResult);
        args.Service = parseResult.GetValueForOption(_serviceOption);
        args.Index = parseResult.GetValueForOption(_indexOption);
        return args;
    }

    [McpServerTool(Destructive = false, ReadOnly = true)]
    public override async Task<CommandResponse> ExecuteAsync(CommandContext context, ParseResult parseResult)
    {
        var args = BindArguments(parseResult);

        try
        {
            if (!await ProcessArguments(context, args))
            {
                return context.Response;
            }

            var searchService = context.GetService<ISearchService>();

            var indexDefinition = await searchService.DescribeIndex(
                args.Service!,
                args.Index!,
                args.RetryPolicy);

            context.Response.Results = indexDefinition != null
                ? ResponseResult.Create(new(indexDefinition), SearchJsonContext.Default.IndexDescribeCommandResult)
                : null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving search index definition");
            HandleException(context.Response, ex);
        }

        return context.Response;
    }

    public sealed record IndexDescribeCommandResult(SearchIndexProxy Index);

    /// <summary>
    /// This record represents the JSON-serialized form of <see cref="SearchIndex"/>
    /// </summary>
    public sealed record SearchIndexProxy()
    {
        public required string Name { get; init; }
        public required List<SearchFieldProxy> Fields { get; init; }

        public sealed record SearchFieldProxy()
        {
            public required string Name { get; init; }
            public required SearchFieldDataType Type { get; init; }
            public bool? Key { get; init; }
            public bool? Searchable { get; init; }
            public bool? Filterable { get; init; }

            [SetsRequiredMembers]
            public SearchFieldProxy(SearchField field) : this()
            {
                Name = field.Name;
                Type = field.Type;
                Key = field.IsKey;
                Searchable = field.IsSearchable;
                Filterable = field.IsFilterable;
            }
        }

        [SetsRequiredMembers]
        public SearchIndexProxy(SearchIndex index) : this()
        {
            Name = index.Name;
            Fields = index.Fields.Select(field => new SearchFieldProxy(field)).ToList();
        }
    }

    private static ArgumentBuilder<IndexDescribeArguments> CreateServiceArgument() =>
        ArgumentBuilder<IndexDescribeArguments>
            .Create(ArgumentDefinitions.Search.Service.Name, ArgumentDefinitions.Search.Service.Description)
            .WithValueAccessor(args => args.Service ?? string.Empty)
            .WithIsRequired(ArgumentDefinitions.Search.Service.Required);

    private static ArgumentBuilder<IndexDescribeArguments> CreateIndexArgument() =>
        ArgumentBuilder<IndexDescribeArguments>
            .Create(ArgumentDefinitions.Search.Index.Name, ArgumentDefinitions.Search.Index.Description)
            .WithValueAccessor(args => args.Index ?? string.Empty)
            .WithIsRequired(ArgumentDefinitions.Search.Index.Required);
}