Remove warnings from build (#29)

* Remove warnings from build

* More fixes.

* Using const for transport types
This commit is contained in:
Toni Wenzel 2025-03-06 21:02:13 +01:00 • committed by GitHub
commit 7d69499ad5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 277 additions and 263 deletions

View file

@ -1,7 +1,7 @@
namespace McpDotNet.Client;
using McpDotNet.Protocol.Types;
using McpDotNet.Protocol.Messages;
using McpDotNet.Protocol.Types;
/// <summary>
/// Represents an instance of the MCP client connecting to a specific server.
@ -35,12 +35,12 @@ public interface IMcpClient : IAsyncDisposable
/// <summary>
/// Gets or sets the handler for server sampling requests.
/// </summary>
Func<CreateMessageRequestParams, CancellationToken, Task<CreateMessageResult>>? SamplingHandler { get; set; }
Func<CreateMessageRequestParams?, CancellationToken, Task<CreateMessageResult>>? SamplingHandler { get; set; }
/// <summary>
/// Gets or sets the handler for providing root URIs to servers.
/// </summary>
Func<ListRootsRequestParams, CancellationToken, Task<ListRootsResult>>? RootsHandler { get; set; }
Func<ListRootsRequestParams?, CancellationToken, Task<ListRootsResult>>? RootsHandler { get; set; }
/// <summary>
/// Establishes a connection to the server.

View file

@ -1,12 +1,12 @@

using McpDotNet.Protocol.Types;
using McpDotNet.Protocol.Transport;
using McpDotNet.Protocol.Messages;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using McpDotNet.Logging;
using McpDotNet.Configuration;
using McpDotNet.Logging;
using McpDotNet.Protocol.Messages;
using McpDotNet.Protocol.Transport;
using McpDotNet.Protocol.Types;
using McpDotNet.Shared;
using Microsoft.Extensions.Logging;
namespace McpDotNet.Client;
@ -46,7 +46,8 @@ internal class McpClient : McpJsonRpcEndpoint, IMcpClient
if (options.Capabilities?.Sampling != null)
{
SetRequestHandler<CreateMessageRequestParams, CreateMessageResult>("sampling/createMessage",
async (request) => {
async (request) =>
{
if (SamplingHandler == null)
{
// Setting the capability, but not a handler means we have nothing to return to the server
@ -168,7 +169,7 @@ internal class McpClient : McpJsonRpcEndpoint, IMcpClient
}
/// <inheritdoc/>
public async Task PingAsync(CancellationToken cancellationToken)
public async Task PingAsync(CancellationToken cancellationToken = default)
{
_logger.PingingServer(EndpointName);
await SendRequestAsync<dynamic>(
@ -268,7 +269,7 @@ internal class McpClient : McpJsonRpcEndpoint, IMcpClient
}
if (argumentValue is null)
{
_logger.InvalidCompletionArgumentValue(EndpointName, argumentValue);
_logger.InvalidCompletionArgumentValue(EndpointName, "null", argumentName);
throw new McpClientException("Argument value cannot be null");
}
@ -330,13 +331,13 @@ internal class McpClient : McpJsonRpcEndpoint, IMcpClient
new JsonRpcRequest
{
Method = "tools/call",
Params = CreateParametersDictionary(toolName, arguments ?? new())
Params = CreateParametersDictionary(toolName, arguments ?? [])
},
cancellationToken
).ConfigureAwait(false);
}
private static Dictionary<string, object?> CreateParametersDictionary(string nameParameter, Dictionary<string, object> arguments)
private static Dictionary<string, object?> CreateParametersDictionary(string nameParameter, Dictionary<string, object>? arguments)
{
var parameters = new Dictionary<string, object?>
{
@ -352,10 +353,10 @@ internal class McpClient : McpJsonRpcEndpoint, IMcpClient
}
/// <inheritdoc/>
public Func<CreateMessageRequestParams, CancellationToken, Task<CreateMessageResult>>? SamplingHandler { get; set; }
public Func<CreateMessageRequestParams?, CancellationToken, Task<CreateMessageResult>>? SamplingHandler { get; set; }
/// <inheritdoc/>
public Func<ListRootsRequestParams, CancellationToken, Task<ListRootsResult>>? RootsHandler { get; set; }
public Func<ListRootsRequestParams?, CancellationToken, Task<ListRootsResult>>? RootsHandler { get; set; }
/// <inheritdoc/>
public override string EndpointName

View file

@ -14,7 +14,7 @@ public class McpClientFactory
{
private readonly Dictionary<string, McpServerConfig> _serverConfigs;
private readonly McpClientOptions _clientOptions;
private readonly Dictionary<string, IMcpClient> _clients = new();
private readonly Dictionary<string, IMcpClient> _clients = [];
private readonly Func<McpServerConfig, IClientTransport> _transportFactoryMethod;
private readonly Func<IClientTransport, McpServerConfig, McpClientOptions, IMcpClient> _clientFactoryMethod;
private readonly ILoggerFactory _loggerFactory;
@ -47,12 +47,9 @@ public class McpClientFactory
// Initialize commands for stdio transport, this is to run commands in a shell even if specified directly, as otherwise
// the stdio protocol will not work correctly.
_logger.InitializingStdioCommands();
foreach (var config in _serverConfigs.Values)
foreach (var config in _serverConfigs.Values.Where(c => c.TransportType.Equals(TransportTypes.StdIo, StringComparison.OrdinalIgnoreCase)))
{
if (config.TransportType.ToLowerInvariant() == "stdio")
{
InitializeCommand(config);
}
InitializeCommand(config);
}
}
@ -97,11 +94,11 @@ public class McpClientFactory
{
string endpointName = $"Client ({config.Id}: {config.Name})";
var options = string.Join(", ", config.TransportOptions?.Select(kv => $"{kv.Key}={kv.Value}") ?? Enumerable.Empty<string>());
var options = string.Join(", ", config.TransportOptions?.Select(kv => $"{kv.Key}={kv.Value}") ?? []);
_logger.CreatingTransport(endpointName, config.TransportType, options);
return config.TransportType.ToLowerInvariant() switch
{
"stdio" => new StdioClientTransport(new StdioClientTransportOptions
TransportTypes.StdIo => new StdioClientTransport(new StdioClientTransportOptions
{
Command = GetCommand(config),
Arguments = config.TransportOptions?.GetValueOrDefault("arguments")?.Split(' '),
@ -110,7 +107,7 @@ public class McpClientFactory
.Where(kv => kv.Key.StartsWith("env:"))
.ToDictionary(kv => kv.Key.Substring(4), kv => kv.Value)
}, config, _loggerFactory),
"sse" or "http" => new SseClientTransport(
TransportTypes.Sse or "http" => new SseClientTransport(
new SseClientTransportOptions
{
ConnectionTimeout = TimeSpan.FromSeconds(ParseOrDefault(config.TransportOptions, "connectionTimeout", 30)),
@ -124,7 +121,7 @@ public class McpClientFactory
};
}
private static int ParseOrDefault(IDictionary<string, string>? options, string key, int defaultValue)
private static int ParseOrDefault(Dictionary<string, string>? options, string key, int defaultValue)
{
if (options?.TryGetValue(key, out var value) ?? false)
{
@ -135,15 +132,14 @@ public class McpClientFactory
return defaultValue;
}
private string? GetCommand(McpServerConfig config)
private static string GetCommand(McpServerConfig config)
{
if (config.TransportOptions == null ||
string.IsNullOrEmpty(config.TransportOptions.GetValueOrDefault("command")))
{
return config.Location!;
}
var command = config.TransportOptions?.GetValueOrDefault("command");
return OperatingSystem.IsWindows() ? "cmd.exe" : config.TransportOptions?.GetValueOrDefault("command");
if (string.IsNullOrEmpty(command))
return config.Location!;
return OperatingSystem.IsWindows() ? "cmd.exe" : command;
}
/// <summary>
@ -162,7 +158,7 @@ public class McpClientFactory
}
// On Windows, we need to wrap non-shell commands with cmd.exe /c
if (command.ToLowerInvariant().Contains("cmd.exe"))
if (command.Contains("cmd.exe", StringComparison.OrdinalIgnoreCase))
{
_logger.SkippingShellWrapper(endpointName);
return;
@ -171,8 +167,8 @@ public class McpClientFactory
// If the command is not empty and does not contain cmd.exe, we need to inject /c {command} (usually npx or uvicorn)
// This is because the stdio transport will not work correctly if the command is not run in a shell
_logger.PromotingCommandToShellArgumentForStdio(endpointName, command, config.TransportOptions!.GetValueOrDefault("arguments") ?? "");
config.TransportOptions!["arguments"] = config.TransportOptions.ContainsKey("arguments")
? $"/c {command} {config.TransportOptions["arguments"]}"
config.TransportOptions!["arguments"] = config.TransportOptions.TryGetValue("arguments", out var args)
? $"/c {command} {args}"
: $"/c {command}";
}
}