Address some static analysis and TODOs (#12)
This commit is contained in:
parent
3de19d38e4
commit
33b9582199
9 changed files with 132 additions and 123 deletions
|
|
@ -6,8 +6,6 @@ using Microsoft.Extensions.AI;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
|
||||
#pragma warning disable CA1508 // Avoid dead conditional code
|
||||
|
||||
namespace ModelContextProtocol.Client;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -439,7 +437,7 @@ public static class McpClientExtensions
|
|||
}
|
||||
|
||||
private static JsonRpcRequest CreateRequest(string method, Dictionary<string, object?>? parameters) =>
|
||||
new JsonRpcRequest
|
||||
new()
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters
|
||||
|
|
|
|||
|
|
@ -30,10 +30,7 @@ public static partial class McpServerBuilderExtensions
|
|||
/// <param name="builder">The builder instance.</param>
|
||||
public static IMcpServerBuilder WithHttpListenerSseServerTransport(this IMcpServerBuilder builder)
|
||||
{
|
||||
if (builder is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
Throw.IfNull(builder);
|
||||
|
||||
builder.Services.AddSingleton<IServerTransport, HttpListenerSseServerTransport>();
|
||||
builder.Services.AddHostedService<McpServerHostedService>();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using ModelContextProtocol.Protocol.Types;
|
||||
using ModelContextProtocol.Server;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ModelContextProtocol.Utils;
|
||||
|
||||
namespace ModelContextProtocol.Configuration;
|
||||
|
||||
|
|
@ -9,10 +10,7 @@ internal sealed class McpServerOptionsSetup(IOptions<McpServerHandlers> serverHa
|
|||
{
|
||||
public void Configure(McpServerOptions options)
|
||||
{
|
||||
if (options is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
Throw.IfNull(options);
|
||||
|
||||
var assemblyName = Assembly.GetEntryAssembly()?.GetName();
|
||||
options.ServerInfo = new Implementation
|
||||
|
|
|
|||
|
|
@ -11,9 +11,12 @@ namespace ModelContextProtocol.Protocol.Transport;
|
|||
[ExcludeFromCodeCoverage]
|
||||
internal class HttpListenerServerProvider : IDisposable
|
||||
{
|
||||
private static readonly byte[] s_accepted = "Accepted"u8.ToArray();
|
||||
|
||||
private const string SseEndpoint = "/sse";
|
||||
private const string MessageEndpoint = "/message";
|
||||
|
||||
private readonly int _port;
|
||||
private readonly string _sseEndpoint = "/sse";
|
||||
private readonly string _messageEndpoint = "/message";
|
||||
private HttpListener? _listener;
|
||||
private CancellationTokenSource? _cts;
|
||||
private Func<string, CancellationToken, bool>? _messageHandler;
|
||||
|
|
@ -31,7 +34,7 @@ internal class HttpListenerServerProvider : IDisposable
|
|||
|
||||
public Task<string> GetSseEndpointUri()
|
||||
{
|
||||
return Task.FromResult($"http://localhost:{_port}{_sseEndpoint}");
|
||||
return Task.FromResult($"http://localhost:{_port}{SseEndpoint}");
|
||||
}
|
||||
|
||||
public Task InitializeMessageHandler(Func<string, CancellationToken, bool> messageHandler)
|
||||
|
|
@ -131,12 +134,12 @@ internal class HttpListenerServerProvider : IDisposable
|
|||
throw new McpServerException("Request is null");
|
||||
|
||||
// Handle SSE connection
|
||||
if (request.HttpMethod == "GET" && request.Url?.LocalPath == _sseEndpoint)
|
||||
if (request.HttpMethod == "GET" && request.Url?.LocalPath == SseEndpoint)
|
||||
{
|
||||
await HandleSseConnectionAsync(context, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
// Handle message POST
|
||||
else if (request.HttpMethod == "POST" && request.Url?.LocalPath == _messageEndpoint)
|
||||
else if (request.HttpMethod == "POST" && request.Url?.LocalPath == MessageEndpoint)
|
||||
{
|
||||
await HandleMessageAsync(context, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
|
@ -167,9 +170,6 @@ internal class HttpListenerServerProvider : IDisposable
|
|||
response.Headers.Add("Cache-Control", "no-cache");
|
||||
response.Headers.Add("Connection", "keep-alive");
|
||||
|
||||
// Create a unique ID for this client
|
||||
var clientId = Guid.NewGuid().ToString();
|
||||
|
||||
// Get the output stream and create a StreamWriter
|
||||
var outputStream = response.OutputStream;
|
||||
_streamWriter = new StreamWriter(outputStream, Encoding.UTF8) { AutoFlush = true };
|
||||
|
|
@ -179,7 +179,7 @@ internal class HttpListenerServerProvider : IDisposable
|
|||
{
|
||||
// Immediately send the "endpoint" event with the POST URL
|
||||
await _streamWriter.WriteLineAsync("event: endpoint").ConfigureAwait(false);
|
||||
await _streamWriter.WriteLineAsync($"data: {_messageEndpoint}").ConfigureAwait(false);
|
||||
await _streamWriter.WriteLineAsync($"data: {MessageEndpoint}").ConfigureAwait(false);
|
||||
await _streamWriter.WriteLineAsync().ConfigureAwait(false); // blank line to end an SSE message
|
||||
await _streamWriter.FlushAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
|
@ -222,10 +222,7 @@ internal class HttpListenerServerProvider : IDisposable
|
|||
string requestBody;
|
||||
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
|
||||
{
|
||||
// TODO: Add cancellation token and netstandard2.0 support (polyfill?)
|
||||
#pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods
|
||||
requestBody = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
#pragma warning restore CA2016 // Forward the 'CancellationToken' parameter to methods
|
||||
requestBody = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Process the message asynchronously
|
||||
|
|
@ -233,12 +230,9 @@ internal class HttpListenerServerProvider : IDisposable
|
|||
{
|
||||
// Return 202 Accepted
|
||||
response.StatusCode = 202;
|
||||
|
||||
// Write "accepted" response
|
||||
// TODO: Use WriteAsync, add cancellation token and netstandard2.0 support (polyfill?)
|
||||
byte[] buffer = Encoding.UTF8.GetBytes("Accepted");
|
||||
#pragma warning disable CA1835 // Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
|
||||
await response.OutputStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
|
||||
#pragma warning restore CA1835 // Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
|
||||
await response.OutputStream.WriteAsync(s_accepted, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using ModelContextProtocol.Protocol.Messages;
|
|||
using ModelContextProtocol.Utils.Json;
|
||||
using ModelContextProtocol.Logging;
|
||||
using ModelContextProtocol.Server;
|
||||
using ModelContextProtocol.Utils;
|
||||
|
||||
namespace ModelContextProtocol.Protocol.Transport;
|
||||
|
||||
|
|
@ -160,15 +161,8 @@ public sealed class HttpListenerSseServerTransport : TransportBase, IServerTrans
|
|||
/// <summary>Validates the <paramref name="serverOptions"/> and extracts from it the server name to use.</summary>
|
||||
private static string GetServerName(McpServerOptions serverOptions)
|
||||
{
|
||||
if (serverOptions is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serverOptions));
|
||||
}
|
||||
|
||||
if (serverOptions.ServerInfo is null)
|
||||
{
|
||||
throw new ArgumentNullException($"{nameof(serverOptions)}.{nameof(serverOptions.ServerInfo)}");
|
||||
}
|
||||
Throw.IfNull(serverOptions);
|
||||
Throw.IfNull(serverOptions.ServerInfo);
|
||||
|
||||
return serverOptions.ServerInfo.Name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ using ModelContextProtocol.Utils.Json;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
#pragma warning disable CA2213 // Disposable fields should be disposed
|
||||
|
||||
namespace ModelContextProtocol.Protocol.Transport;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ using Microsoft.Extensions.Logging;
|
|||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
#pragma warning disable CA2208 // Instantiate argument exceptions correctly
|
||||
#pragma warning disable CA2213 // Disposable fields should be disposed
|
||||
|
||||
namespace ModelContextProtocol.Protocol.Transport;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ internal abstract class McpJsonRpcEndpoint : IAsyncDisposable
|
|||
#if NET
|
||||
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
|
||||
#else
|
||||
await Task.Yield(); // TODO: Fix this
|
||||
await default(ForceYielding);
|
||||
#endif
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ internal static class Throw
|
|||
{
|
||||
if (arg is null || arg.AsSpan().IsWhiteSpace())
|
||||
{
|
||||
ThrowArgumentNullOrWhiteSpaceException(arg);
|
||||
ThrowArgumentNullOrWhiteSpaceException(parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue