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
61 changes: 48 additions & 13 deletions SharpTools.SseServer/Program.cs
Original file line number Diff line number Diff line change
@@ -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 ---
Expand Down Expand Up @@ -58,13 +59,25 @@ public static async Task<int> Main(string[] args) {
DefaultValueFactory = x => false
};

var listToolsOption = new Option<bool>("--list-tools") {
Description = "List available tool and prompt type names, then exit.",
DefaultValueFactory = x => false
};

var excludeToolTypesOption = new Option<List<string>>("--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);
Expand All @@ -80,6 +93,8 @@ public static async Task<int> Main(string[] args) {
string? buildConfiguration = parseResult.GetValue(buildConfigurationOption)!;
bool disableGit = parseResult.GetValue(disableGitOption);
string serverUrl = $"http://localhost:{port}";
bool listTools = parseResult.GetValue(listToolsOption);
List<string> excludeToolTypes = parseResult.GetValue(excludeToolTypesOption) ?? [];

var loggerConfiguration = new LoggerConfiguration()
.MinimumLevel.Is(minimumLogLevel) // Set based on command line
Expand Down Expand Up @@ -124,6 +139,26 @@ public static async Task<int> 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<McpServerToolTypeAttribute>() 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<McpServerToolAttribute>() is not null)
.OrderBy(m => m.Name)) {
var attr = m.GetCustomAttribute<McpServerToolAttribute>()!;
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);
Expand Down Expand Up @@ -155,7 +190,7 @@ public static async Task<int> Main(string[] args) {
// but ModelContextProtocol's own Debug logging should be sufficient.
})
.WithHttpTransport()
.WithSharpTools();
.WithSharpTools(excludeToolTypes);

var app = builder.Build();

Expand Down
60 changes: 44 additions & 16 deletions SharpTools.StdioServer/Program.cs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -48,12 +42,24 @@ public static async Task<int> Main(string[] args) {
DefaultValueFactory = x => false
};

var listToolsOption = new Option<bool>("--list-tools") {
Description = "List available tool and prompt type names, then exit.",
DefaultValueFactory = x => false
};

var excludeToolTypesOption = new Option<List<string>>("--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);
Expand All @@ -67,6 +73,8 @@ public static async Task<int> Main(string[] args) {
string? solutionPath = parseResult.GetValue(loadSolutionOption);
string? buildConfiguration = parseResult.GetValue(buildConfigurationOption)!;
bool disableGit = parseResult.GetValue(disableGitOption);
bool listTools = parseResult.GetValue(listToolsOption);
List<string> excludeToolTypes = parseResult.GetValue(excludeToolTypesOption) ?? [];

var loggerConfiguration = new LoggerConfiguration()
.MinimumLevel.Is(minimumLogLevel)
Expand Down Expand Up @@ -116,6 +124,26 @@ public static async Task<int> 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<McpServerToolTypeAttribute>() 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<McpServerToolAttribute>() is not null)
.OrderBy(m => m.Name)) {
var attr = m.GetCustomAttribute<McpServerToolAttribute>()!;
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();
Expand All @@ -129,7 +157,7 @@ public static async Task<int> Main(string[] args) {
};
})
.WithStdioServerTransport()
.WithSharpTools();
.WithSharpTools(excludeToolTypes);

try {
Log.Information("Starting {AppName} v{AppVersion}", ApplicationName, ApplicationVersion);
Expand Down
17 changes: 9 additions & 8 deletions SharpTools.Tools/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
Expand Down Expand Up @@ -44,12 +38,19 @@ public static IServiceCollection WithSharpToolsServices(this IServiceCollection
/// Adds all SharpTools services and tools to the MCP service builder.
/// </summary>
/// <param name="builder">The MCP service builder.</param>
/// <param name="exclude">Tool assembly type names to exclude (e.g. AnalysisTools).</param>
/// <returns>The MCP service builder for chaining.</returns>
public static IMcpServerBuilder WithSharpTools(this IMcpServerBuilder builder) {
public static IMcpServerBuilder WithSharpTools(this IMcpServerBuilder builder, List<string> exclude) {
var toolAssembly = Assembly.Load("SharpTools.Tools");
var excludedSet = new HashSet<string>(exclude);

var tools = from t in toolAssembly.GetTypes()
where t.GetCustomAttribute<McpServerToolTypeAttribute>() is not null
&& !excludedSet.Contains(t.Name)
select t;

return builder
.WithToolsFromAssembly(toolAssembly)
.WithTools(tools)
.WithPromptsFromAssembly(toolAssembly);
}
}