-
Couldn't load subscription status.
- Fork 257
Add a command listing all the tool names #741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
fanyang-mono
wants to merge
12
commits into
microsoft:main
Choose a base branch
from
fanyang-mono:list_tool_names
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e47f467
Add a command listing all tool names
fanyang-mono f311a5c
Add --namespace option to scope it down to a specific namespace
fanyang-mono 939c2b4
Fix format
fanyang-mono 117e3a1
Add --name switch to tool list command to only return tool names
fanyang-mono d9f5332
Merge remote-tracking branch 'origin/main' into list_tool_names
fanyang-mono 7459e1f
Update CHANGELOG
fanyang-mono 325dc3f
Create a helper function to reuse the namespace filtering logic
fanyang-mono ca614ac
Merge remote-tracking branch 'origin/main' into list_tool_names
fanyang-mono 785390b
Fix format
fanyang-mono 1a9f02d
Merge branch 'main' into list_tool_names
fanyang-mono f54b5d8
Fix test failure
fanyang-mono 2c2c325
Merge remote-tracking branch 'origin/main' into list_tool_names
fanyang-mono File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
89 changes: 89 additions & 0 deletions
89
core/Azure.Mcp.Core/src/Areas/Tools/Commands/ToolsListNamesCommand.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.CommandLine.Parsing; | ||
| using Azure.Mcp.Core.Areas.Tools.Options; | ||
| using Azure.Mcp.Core.Commands; | ||
| using Azure.Mcp.Core.Extensions; | ||
| using Azure.Mcp.Core.Models; | ||
| using Azure.Mcp.Core.Models.Command; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Azure.Mcp.Core.Areas.Tools.Commands; | ||
|
|
||
| [HiddenCommand] | ||
| public sealed class ToolsListNamesCommand(ILogger<ToolsListNamesCommand> logger) : BaseCommand<ToolsListNamesOptions> | ||
| { | ||
| private const string CommandTitle = "List Tool Names"; | ||
|
|
||
| public override string Name => "list-names"; | ||
|
|
||
| public override string Description => | ||
| """ | ||
| List all available tool names in the Azure MCP server. This command returns a simple list of tool names | ||
| without descriptions or metadata, useful for quick discovery or automated tool enumeration. | ||
| """; | ||
|
|
||
| public override string Title => CommandTitle; | ||
|
|
||
| public override ToolMetadata Metadata => new() | ||
| { | ||
| Destructive = false, | ||
| Idempotent = true, | ||
| OpenWorld = false, | ||
| ReadOnly = true, | ||
| LocalRequired = false, | ||
| Secret = false | ||
| }; | ||
|
|
||
| protected override void RegisterOptions(Command command) | ||
| { | ||
| base.RegisterOptions(command); | ||
| command.Options.Add(ToolsListOptionDefinitions.Namespace); | ||
| } | ||
|
|
||
| protected override ToolsListNamesOptions BindOptions(ParseResult parseResult) | ||
| { | ||
| var options = new ToolsListNamesOptions(); | ||
| options.Namespace = parseResult.GetValueOrDefault<string>(ToolsListOptionDefinitions.Namespace.Name); | ||
| return options; | ||
| } | ||
|
|
||
| public override async Task<CommandResponse> ExecuteAsync(CommandContext context, ParseResult parseResult) | ||
| { | ||
| try | ||
| { | ||
| var factory = context.GetService<CommandFactory>(); | ||
| var options = BindOptions(parseResult); | ||
|
|
||
| // Get all visible commands and extract their tokenized names (full command paths) | ||
| var allToolNames = CommandFactory.GetVisibleCommands(factory.AllCommands) | ||
| .Select(kvp => kvp.Key) // Use the tokenized key instead of just the command name | ||
| .Where(name => !string.IsNullOrEmpty(name)); | ||
|
|
||
| // Apply namespace filtering if specified | ||
| if (!string.IsNullOrEmpty(options.Namespace)) | ||
| { | ||
| var namespacePrefix = $"azmcp_{options.Namespace}_"; | ||
| allToolNames = allToolNames.Where(name => name.StartsWith(namespacePrefix, StringComparison.OrdinalIgnoreCase)); | ||
| } | ||
|
|
||
| var toolNames = await Task.Run(() => allToolNames | ||
| .OrderBy(name => name, StringComparer.OrdinalIgnoreCase) | ||
| .ToList()); | ||
|
|
||
| var result = new ToolNamesResult(toolNames); | ||
| context.Response.Results = ResponseResult.Create(result, ModelsJsonContext.Default.ToolNamesResult); | ||
| return context.Response; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| logger.LogError(ex, "An exception occurred while processing tool names listing."); | ||
| HandleException(context, ex); | ||
|
|
||
| return context.Response; | ||
| } | ||
| } | ||
|
|
||
| public record ToolNamesResult(List<string> Names); | ||
| } | ||
12 changes: 12 additions & 0 deletions
12
core/Azure.Mcp.Core/src/Areas/Tools/Options/ToolsListNamesOptions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace Azure.Mcp.Core.Areas.Tools.Options; | ||
|
|
||
| public sealed class ToolsListNamesOptions | ||
| { | ||
| /// <summary> | ||
| /// Optional namespace to filter tool names. If provided, only tools from this namespace will be returned. | ||
| /// </summary> | ||
| public string? Namespace { get; set; } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
...p.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Tools/UnitTests/ToolsListNamesCommandTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.CommandLine; | ||
| using System.CommandLine.Parsing; | ||
| using System.Net; | ||
| using System.Text.Json; | ||
| using Azure.Mcp.Core.Areas; | ||
| using Azure.Mcp.Core.Areas.Tools.Commands; | ||
| using Azure.Mcp.Core.Areas.Tools.Options; | ||
| using Azure.Mcp.Core.Commands; | ||
| using Azure.Mcp.Core.Extensions; | ||
| using Azure.Mcp.Core.Models.Command; | ||
| using Azure.Mcp.Core.Services.Telemetry; | ||
| using Azure.Mcp.Core.UnitTests.Areas.Server; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| using NSubstitute; | ||
| using Xunit; | ||
|
|
||
| namespace Azure.Mcp.Core.UnitTests.Areas.Tools.UnitTests; | ||
|
|
||
| public class ToolsListNamesCommandTests | ||
| { | ||
| private readonly IServiceProvider _serviceProvider; | ||
| private readonly ILogger<ToolsListNamesCommand> _logger; | ||
| private readonly CommandContext _context; | ||
| private readonly ToolsListNamesCommand _command; | ||
| private readonly Command _commandDefinition; | ||
|
|
||
| public ToolsListNamesCommandTests() | ||
| { | ||
| var collection = new ServiceCollection(); | ||
| collection.AddLogging(); | ||
|
|
||
| var commandFactory = CommandFactoryHelpers.CreateCommandFactory(); | ||
| collection.AddSingleton(commandFactory); | ||
|
|
||
| _serviceProvider = collection.BuildServiceProvider(); | ||
| _context = new(_serviceProvider); | ||
| _logger = Substitute.For<ILogger<ToolsListNamesCommand>>(); | ||
| _command = new(_logger); | ||
| _commandDefinition = _command.GetCommand(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Constructor_InitializesCommandCorrectly() | ||
| { | ||
| // Act & Assert | ||
| Assert.Equal("list-names", _command.Name); | ||
| Assert.Contains("List all available tool names", _command.Description); | ||
| Assert.Equal("List Tool Names", _command.Title); | ||
| Assert.False(_command.Metadata.Destructive); | ||
| Assert.True(_command.Metadata.ReadOnly); | ||
| Assert.True(_command.Metadata.Idempotent); | ||
| Assert.False(_command.Metadata.Secret); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void CanParseNamespaceOption() | ||
| { | ||
| // Arrange | ||
| var commandDefinition = _command.GetCommand(); | ||
|
|
||
| // Act | ||
| var parseResult = commandDefinition.Parse(["--namespace", "storage"]); | ||
|
|
||
| // Assert | ||
| Assert.NotNull(parseResult); | ||
| Assert.False(parseResult.Errors.Any(), $"Parse errors: {string.Join(", ", parseResult.Errors)}"); | ||
|
|
||
| var namespaceValue = parseResult.GetValueOrDefault<string>(ToolsListOptionDefinitions.Namespace.Name); | ||
| Assert.Equal("storage", namespaceValue); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task ExecuteAsync_WithNamespaceOption_FiltersCorrectly() | ||
| { | ||
| // Arrange | ||
| var commandDefinition = _command.GetCommand(); | ||
| var parseResult = commandDefinition.Parse(["--namespace", "storage"]); | ||
|
|
||
| // Act | ||
| var response = await _command.ExecuteAsync(_context, parseResult); | ||
|
|
||
| // Assert | ||
| Assert.NotNull(response); | ||
| Assert.Equal(HttpStatusCode.OK, response.Status); | ||
| // Note: We're not testing response.Results here since it's null in the test environment | ||
| // but we can verify the command executes without errors | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.