From deb8e9f98359487af3ce76f54aa23d3a68ea0a82 Mon Sep 17 00:00:00 2001 From: Kyu Date: Tue, 10 Feb 2026 12:34:15 -0600 Subject: [PATCH] Add `--exclude-tool-types` and `--list-tools` flags. Addresses https://github.com/kooshi/SharpToolsMCP/issues/13 --- SharpTools.SseServer/Program.cs | 61 +++++++++++++++---- SharpTools.StdioServer/Program.cs | 60 +++++++++++++----- .../Extensions/ServiceCollectionExtensions.cs | 17 +++--- 3 files changed, 101 insertions(+), 37 deletions(-) diff --git a/SharpTools.SseServer/Program.cs b/SharpTools.SseServer/Program.cs index e1a4a46..1cead02 100644 --- a/SharpTools.SseServer/Program.cs +++ b/SharpTools.SseServer/Program.cs @@ -1,24 +1,25 @@ -using SharpTools.Tools.Services; -using SharpTools.Tools.Interfaces; -using SharpTools.Tools.Mcp.Tools; -using SharpTools.Tools.Extensions; using System.CommandLine; using System.CommandLine.Parsing; +using System.Reflection; using Microsoft.AspNetCore.HttpLogging; -using Serilog; using ModelContextProtocol.Protocol; -using System.Reflection; -namespace SharpTools.SseServer; - -using SharpTools.Tools.Services; +using Serilog; +using SharpTools.Tools.Extensions; using SharpTools.Tools.Interfaces; using SharpTools.Tools.Mcp.Tools; +using SharpTools.Tools.Services; +namespace SharpTools.SseServer; + using System.CommandLine; using System.CommandLine.Parsing; +using System.Reflection; using Microsoft.AspNetCore.HttpLogging; -using Serilog; using ModelContextProtocol.Protocol; -using System.Reflection; +using ModelContextProtocol.Server; +using Serilog; +using SharpTools.Tools.Interfaces; +using SharpTools.Tools.Mcp.Tools; +using SharpTools.Tools.Services; public class Program { // --- Application --- @@ -58,13 +59,25 @@ public static async Task Main(string[] args) { DefaultValueFactory = x => false }; + var listToolsOption = new Option("--list-tools") { + Description = "List available tool and prompt type names, then exit.", + DefaultValueFactory = x => false + }; + + var excludeToolTypesOption = new Option>("--exclude-tool-types") { + Description = "List of tool type names to exclude (from --list-tools).", + AllowMultipleArgumentsPerToken = true + }; + var rootCommand = new RootCommand("SharpTools MCP Server") { portOption, logFileOption, logLevelOption, loadSolutionOption, buildConfigurationOption, - disableGitOption + disableGitOption, + listToolsOption, + excludeToolTypesOption, }; ParseResult? parseResult = rootCommand.Parse(args); @@ -80,6 +93,8 @@ public static async Task Main(string[] args) { string? buildConfiguration = parseResult.GetValue(buildConfigurationOption)!; bool disableGit = parseResult.GetValue(disableGitOption); string serverUrl = $"http://localhost:{port}"; + bool listTools = parseResult.GetValue(listToolsOption); + List excludeToolTypes = parseResult.GetValue(excludeToolTypesOption) ?? []; var loggerConfiguration = new LoggerConfiguration() .MinimumLevel.Is(minimumLogLevel) // Set based on command line @@ -124,6 +139,26 @@ public static async Task Main(string[] args) { Log.Information("Using build configuration: {BuildConfiguration}", buildConfiguration); } + if (listTools) { + var toolAssembly = Assembly.Load("SharpTools.Tools"); + + Console.WriteLine("Tools:"); + foreach (var t in toolAssembly.GetTypes() + .Where(t => t.GetCustomAttribute() is not null) + .OrderBy(t => t.Name)) { + Console.WriteLine($" {t.Name}"); + foreach (var m in t.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance) + .Where(m => m.GetCustomAttribute() is not null) + .OrderBy(m => m.Name)) { + var attr = m.GetCustomAttribute()!; + var name = string.IsNullOrEmpty(attr.Name) ? m.Name : attr.Name; + Console.WriteLine($" - {name}"); + } + } + + return 0; + } + try { Log.Information("Configuring {AppName} v{AppVersion} to run on {ServerUrl} with minimum log level {LogLevel}", ApplicationName, ApplicationVersion, serverUrl, minimumLogLevel); @@ -155,7 +190,7 @@ public static async Task Main(string[] args) { // but ModelContextProtocol's own Debug logging should be sufficient. }) .WithHttpTransport() - .WithSharpTools(); + .WithSharpTools(excludeToolTypes); var app = builder.Build(); diff --git a/SharpTools.StdioServer/Program.cs b/SharpTools.StdioServer/Program.cs index f78f780..bd7239e 100644 --- a/SharpTools.StdioServer/Program.cs +++ b/SharpTools.StdioServer/Program.cs @@ -1,20 +1,14 @@ -using SharpTools.Tools.Services; -using SharpTools.Tools.Interfaces; -using SharpTools.Tools.Mcp.Tools; -using SharpTools.Tools.Extensions; -using Serilog; -using System.CommandLine; -using System.CommandLine.Parsing; +using System.CommandLine; using System.Reflection; -using ModelContextProtocol.Protocol; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using System.IO; -using System; -using System.Threading.Tasks; -using System.Threading; - +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; +using Serilog; +using SharpTools.Tools.Extensions; +using SharpTools.Tools.Interfaces; +using SharpTools.Tools.Mcp.Tools; namespace SharpTools.StdioServer; public static class Program { @@ -48,12 +42,24 @@ public static async Task Main(string[] args) { DefaultValueFactory = x => false }; + var listToolsOption = new Option("--list-tools") { + Description = "List available tool and prompt type names, then exit.", + DefaultValueFactory = x => false + }; + + var excludeToolTypesOption = new Option>("--exclude-tool-types") { + Description = "List of tool type names to exclude (from --list-tools).", + AllowMultipleArgumentsPerToken = true + }; + var rootCommand = new RootCommand("SharpTools MCP StdIO Server"){ logDirOption, logLevelOption, loadSolutionOption, buildConfigurationOption, - disableGitOption + disableGitOption, + listToolsOption, + excludeToolTypesOption, }; ParseResult? parseResult = rootCommand.Parse(args); @@ -67,6 +73,8 @@ public static async Task Main(string[] args) { string? solutionPath = parseResult.GetValue(loadSolutionOption); string? buildConfiguration = parseResult.GetValue(buildConfigurationOption)!; bool disableGit = parseResult.GetValue(disableGitOption); + bool listTools = parseResult.GetValue(listToolsOption); + List excludeToolTypes = parseResult.GetValue(excludeToolTypesOption) ?? []; var loggerConfiguration = new LoggerConfiguration() .MinimumLevel.Is(minimumLogLevel) @@ -116,6 +124,26 @@ public static async Task Main(string[] args) { Log.Information("Using build configuration: {BuildConfiguration}", buildConfiguration); } + if(listTools) { + var toolAssembly = Assembly.Load("SharpTools.Tools"); + + Console.WriteLine("Tools:"); + foreach (var t in toolAssembly.GetTypes() + .Where(t => t.GetCustomAttribute() is not null) + .OrderBy(t => t.Name)) { + Console.WriteLine($" {t.Name}"); + foreach (var m in t.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance) + .Where(m => m.GetCustomAttribute() is not null) + .OrderBy(m => m.Name)) { + var attr = m.GetCustomAttribute()!; + var name = string.IsNullOrEmpty(attr.Name) ? m.Name : attr.Name; + Console.WriteLine($" - {name}"); + } + } + + return 0; + } + var builder = Host.CreateApplicationBuilder(args); builder.Logging.ClearProviders(); builder.Logging.AddSerilog(); @@ -129,7 +157,7 @@ public static async Task Main(string[] args) { }; }) .WithStdioServerTransport() - .WithSharpTools(); + .WithSharpTools(excludeToolTypes); try { Log.Information("Starting {AppName} v{AppVersion}", ApplicationName, ApplicationVersion); diff --git a/SharpTools.Tools/Extensions/ServiceCollectionExtensions.cs b/SharpTools.Tools/Extensions/ServiceCollectionExtensions.cs index 4a7a509..595910c 100644 --- a/SharpTools.Tools/Extensions/ServiceCollectionExtensions.cs +++ b/SharpTools.Tools/Extensions/ServiceCollectionExtensions.cs @@ -1,9 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using SharpTools.Tools.Interfaces; -using SharpTools.Tools.Services; -using System.Reflection; - namespace SharpTools.Tools.Extensions; /// @@ -44,12 +38,19 @@ public static IServiceCollection WithSharpToolsServices(this IServiceCollection /// Adds all SharpTools services and tools to the MCP service builder. /// /// The MCP service builder. + /// Tool assembly type names to exclude (e.g. AnalysisTools). /// The MCP service builder for chaining. - public static IMcpServerBuilder WithSharpTools(this IMcpServerBuilder builder) { + public static IMcpServerBuilder WithSharpTools(this IMcpServerBuilder builder, List exclude) { var toolAssembly = Assembly.Load("SharpTools.Tools"); + var excludedSet = new HashSet(exclude); + + var tools = from t in toolAssembly.GetTypes() + where t.GetCustomAttribute() is not null + && !excludedSet.Contains(t.Name) + select t; return builder - .WithToolsFromAssembly(toolAssembly) + .WithTools(tools) .WithPromptsFromAssembly(toolAssembly); } } \ No newline at end of file