diff --git a/Directory.Packages.props b/Directory.Packages.props index 2d8f454e8..adb9b43d1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,9 +1,9 @@ true - 9.0.5 - 10.0.0-preview.4.25258.110 - 9.9.1 + 9.0.10 + 10.0.0-rc.2.25502.107 + 9.10.0 @@ -28,19 +28,17 @@ - + - - + - @@ -56,19 +54,19 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + diff --git a/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs b/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs index b907a805d..1528fa5a6 100644 --- a/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs +++ b/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs @@ -73,7 +73,7 @@ CancellationToken token string? playerName = nameResponse.Content?["Name"].GetString(); // Generate a random number between 1 and 10 - Random random = new Random(); + Random random = new(); int targetNumber = random.Next(1, 11); // 1 to 10 inclusive int attempts = 0; diff --git a/samples/AspNetCoreMcpPerSessionTools/Program.cs b/samples/AspNetCoreMcpPerSessionTools/Program.cs index 3484978ec..b9174cd7a 100644 --- a/samples/AspNetCoreMcpPerSessionTools/Program.cs +++ b/samples/AspNetCoreMcpPerSessionTools/Program.cs @@ -24,7 +24,7 @@ { mcpOptions.Capabilities = new(); mcpOptions.Capabilities.Tools = new(); - var toolCollection = mcpOptions.ToolCollection = new(); + var toolCollection = mcpOptions.ToolCollection = []; foreach (var tool in tools) { diff --git a/src/Common/CancellableStreamReader/CancellableStreamReader.cs b/src/Common/CancellableStreamReader/CancellableStreamReader.cs index f6df72d22..9bc9ac6ac 100644 --- a/src/Common/CancellableStreamReader/CancellableStreamReader.cs +++ b/src/Common/CancellableStreamReader/CancellableStreamReader.cs @@ -350,7 +350,7 @@ public override string ReadToEnd() CheckAsyncTaskInProgress(); // Call ReadBuffer, then pull data out of charBuffer. - StringBuilder sb = new StringBuilder(_charLen - _charPos); + StringBuilder sb = new(_charLen - _charPos); do { sb.Append(_charBuffer, _charPos, _charLen - _charPos); @@ -953,7 +953,7 @@ public virtual Task ReadToEndAsync(CancellationToken cancellationToken) private async Task ReadToEndAsyncInternal(CancellationToken cancellationToken) { // Call ReadBuffer, then pull data out of charBuffer. - StringBuilder sb = new StringBuilder(_charLen - _charPos); + StringBuilder sb = new(_charLen - _charPos); do { int tmpCharPos = _charPos; diff --git a/src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationOptions.cs b/src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationOptions.cs index ecb6c6c82..c7280e455 100644 --- a/src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationOptions.cs +++ b/src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationOptions.cs @@ -25,9 +25,9 @@ public McpAuthenticationOptions() /// Gets or sets the events used to handle authentication events. /// public new McpAuthenticationEvents Events - { - get { return (McpAuthenticationEvents)base.Events!; } - set { base.Events = value; } + { + get => (McpAuthenticationEvents)base.Events!; + set => base.Events = value; } /// diff --git a/src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs b/src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs index dce594e2e..ae5e42dd8 100644 --- a/src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs +++ b/src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs @@ -55,7 +55,7 @@ await FilterAuthorizedItemsAsync( }); } - private void CheckListToolsFilter(McpServerOptions options) + private static void CheckListToolsFilter(McpServerOptions options) { options.Filters.ListToolsFilters.Add(next => async (context, cancellationToken) => { @@ -87,7 +87,7 @@ private void ConfigureCallToolFilter(McpServerOptions options) }); } - private void CheckCallToolFilter(McpServerOptions options) + private static void CheckCallToolFilter(McpServerOptions options) { options.Filters.CallToolFilters.Add(next => async (context, cancellationToken) => { @@ -115,7 +115,7 @@ await FilterAuthorizedItemsAsync( }); } - private void CheckListResourcesFilter(McpServerOptions options) + private static void CheckListResourcesFilter(McpServerOptions options) { options.Filters.ListResourcesFilters.Add(next => async (context, cancellationToken) => { @@ -145,7 +145,7 @@ await FilterAuthorizedItemsAsync( }); } - private void CheckListResourceTemplatesFilter(McpServerOptions options) + private static void CheckListResourceTemplatesFilter(McpServerOptions options) { options.Filters.ListResourceTemplatesFilters.Add(next => async (context, cancellationToken) => { @@ -177,7 +177,7 @@ private void ConfigureReadResourceFilter(McpServerOptions options) }); } - private void CheckReadResourceFilter(McpServerOptions options) + private static void CheckReadResourceFilter(McpServerOptions options) { options.Filters.ReadResourceFilters.Add(next => async (context, cancellationToken) => { @@ -205,7 +205,7 @@ await FilterAuthorizedItemsAsync( }); } - private void CheckListPromptsFilter(McpServerOptions options) + private static void CheckListPromptsFilter(McpServerOptions options) { options.Filters.ListPromptsFilters.Add(next => async (context, cancellationToken) => { @@ -237,7 +237,7 @@ private void ConfigureGetPromptFilter(McpServerOptions options) }); } - private void CheckGetPromptFilter(McpServerOptions options) + private static void CheckGetPromptFilter(McpServerOptions options) { options.Filters.GetPromptFilters.Add(next => async (context, cancellationToken) => { diff --git a/src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj b/src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj index 7968e23f8..a957bd969 100644 --- a/src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj +++ b/src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0 + net10.0;net9.0;net8.0 enable enable true diff --git a/src/ModelContextProtocol.Core/AIContentExtensions.cs b/src/ModelContextProtocol.Core/AIContentExtensions.cs index 6b6a9c780..b792bc1af 100644 --- a/src/ModelContextProtocol.Core/AIContentExtensions.cs +++ b/src/ModelContextProtocol.Core/AIContentExtensions.cs @@ -128,10 +128,7 @@ public static IList ToPromptMessages(this ChatMessage chatMessage _ => null, }; - if (ac is not null) - { - ac.RawRepresentation = content; - } + ac?.RawRepresentation = content; return ac; } diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs index b72f775c4..468728982 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs @@ -1,5 +1,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +#if NET9_0_OR_GREATER +using System.Buffers.Text; +#endif using System.Diagnostics.CodeAnalysis; using System.Net.Http.Headers; using System.Security.Cryptography; @@ -238,14 +241,17 @@ private async Task PerformOAuthAuthorizationAsync( LogOAuthAuthorizationCompleted(); } + private static readonly string[] s_wellKnownPaths = [".well-known/openid-configuration", ".well-known/oauth-authorization-server"]; + private async Task GetAuthServerMetadataAsync(Uri authServerUri, CancellationToken cancellationToken) { - if (!authServerUri.OriginalString.EndsWith("/")) + if (authServerUri.OriginalString.Length == 0 || + authServerUri.OriginalString[authServerUri.OriginalString.Length - 1] != '/') { - authServerUri = new Uri(authServerUri.OriginalString + "/"); + authServerUri = new Uri($"{authServerUri.OriginalString}/"); } - foreach (var path in new[] { ".well-known/openid-configuration", ".well-known/oauth-authorization-server" }) + foreach (var path in s_wellKnownPaths) { try { @@ -540,11 +546,7 @@ private static string NormalizeUri(Uri uri) Port = -1 // Always remove port }; - if (builder.Path == "/") - { - builder.Path = string.Empty; - } - else if (builder.Path.Length > 1 && builder.Path.EndsWith("/")) + if (builder.Path.Length > 0 && builder.Path[builder.Path.Length - 1] == '/') { builder.Path = builder.Path.TrimEnd('/'); } @@ -633,18 +635,18 @@ private async Task ExtractProtectedResourceMetadata(H continue; } - string key = trimmedPart.Substring(0, equalsIndex).Trim(); + ReadOnlySpan key = trimmedPart.AsSpan().Slice(0, equalsIndex).Trim(); - if (string.Equals(key, parameterName, StringComparison.OrdinalIgnoreCase)) + if (key.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) { - string value = trimmedPart.Substring(equalsIndex + 1).Trim(); + ReadOnlySpan value = trimmedPart.AsSpan(equalsIndex + 1).Trim(); - if (value.StartsWith("\"") && value.EndsWith("\"")) + if (value.Length > 0 && value[0] == '"' && value[value.Length - 1] == '"') { - value = value.Substring(1, value.Length - 2); + value = value.Slice(1, value.Length - 2); } - return value; + return value.ToString(); } } @@ -664,12 +666,18 @@ private static string GenerateCodeVerifier() private static string GenerateCodeChallenge(string codeVerifier) { +#if NET9_0_OR_GREATER + Span hash = stackalloc byte[SHA256.HashSizeInBytes]; + SHA256.HashData(Encoding.UTF8.GetBytes(codeVerifier), hash); + return Base64Url.EncodeToString(hash); +#else using var sha256 = SHA256.Create(); var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); return Convert.ToBase64String(challengeBytes) .TrimEnd('=') .Replace('+', '-') .Replace('/', '_'); +#endif } private string GetClientIdOrThrow() => _clientId ?? throw new InvalidOperationException("Client ID is not available. This may indicate an issue with dynamic client registration."); diff --git a/src/ModelContextProtocol.Core/Client/McpClientOptions.cs b/src/ModelContextProtocol.Core/Client/McpClientOptions.cs index ff71f5899..622539386 100644 --- a/src/ModelContextProtocol.Core/Client/McpClientOptions.cs +++ b/src/ModelContextProtocol.Core/Client/McpClientOptions.cs @@ -11,8 +11,6 @@ namespace ModelContextProtocol.Client; /// public sealed class McpClientOptions { - private McpClientHandlers? _handlers; - /// /// Gets or sets information about this client implementation, including its name and version. /// @@ -71,11 +69,11 @@ public sealed class McpClientOptions /// public McpClientHandlers Handlers { - get => _handlers ??= new(); + get => field ??= new(); set { Throw.IfNull(value); - _handlers = value; + field = value; } } } diff --git a/src/ModelContextProtocol.Core/Client/StdioClientSessionTransport.cs b/src/ModelContextProtocol.Core/Client/StdioClientSessionTransport.cs index 2ce32cb72..a9c228d43 100644 --- a/src/ModelContextProtocol.Core/Client/StdioClientSessionTransport.cs +++ b/src/ModelContextProtocol.Core/Client/StdioClientSessionTransport.cs @@ -5,21 +5,15 @@ namespace ModelContextProtocol.Client; /// Provides the client side of a stdio-based session transport. -internal sealed class StdioClientSessionTransport : StreamClientSessionTransport +internal sealed class StdioClientSessionTransport( + StdioClientTransportOptions options, Process process, string endpointName, Queue stderrRollingLog, ILoggerFactory? loggerFactory) : + StreamClientSessionTransport(process.StandardInput.BaseStream, process.StandardOutput.BaseStream, encoding: null, endpointName, loggerFactory) { - private readonly StdioClientTransportOptions _options; - private readonly Process _process; - private readonly Queue _stderrRollingLog; + private readonly StdioClientTransportOptions _options = options; + private readonly Process _process = process; + private readonly Queue _stderrRollingLog = stderrRollingLog; private int _cleanedUp = 0; - public StdioClientSessionTransport(StdioClientTransportOptions options, Process process, string endpointName, Queue stderrRollingLog, ILoggerFactory? loggerFactory) - : base(process.StandardInput.BaseStream, process.StandardOutput.BaseStream, encoding: null, endpointName, loggerFactory) - { - _process = process; - _options = options; - _stderrRollingLog = stderrRollingLog; - } - /// public override async Task SendMessageAsync(JsonRpcMessage message, CancellationToken cancellationToken = default) { @@ -56,7 +50,7 @@ protected override async ValueTask CleanupAsync(Exception? error = null, Cancell // Now terminate the server process. try { - StdioClientTransport.DisposeProcess(_process, processRunning: true, _options.ShutdownTimeout, Name); + StdioClientTransport.DisposeProcess(_process, processRunning: true, shutdownTimeout: _options.ShutdownTimeout); } catch (Exception ex) { diff --git a/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs b/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs index 3ec0d2880..f3e624159 100644 --- a/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs +++ b/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs @@ -39,7 +39,7 @@ public StdioClientTransport(StdioClientTransportOptions options, ILoggerFactory? _options = options; _loggerFactory = loggerFactory; - Name = options.Name ?? $"stdio-{Regex.Replace(Path.GetFileName(options.Command), @"[\s\.]+", "-")}"; + Name = options.Name ?? $"stdio-{WhitespaceAndPeriods().Replace(Path.GetFileName(options.Command), "-")}"; } /// @@ -189,7 +189,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken = try { - DisposeProcess(process, processStarted, _options.ShutdownTimeout, endpointName); + DisposeProcess(process, processStarted, _options.ShutdownTimeout); } catch (Exception ex2) { @@ -201,7 +201,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken = } internal static void DisposeProcess( - Process? process, bool processRunning, TimeSpan shutdownTimeout, string endpointName) + Process? process, bool processRunning, TimeSpan shutdownTimeout) { if (process is not null) { @@ -279,4 +279,12 @@ private static string EscapeArgumentString(string argument) => [LoggerMessage(Level = LogLevel.Warning, Message = "{EndpointName} shutdown failed.")] private static partial void LogTransportShutdownFailed(ILogger logger, string endpointName, Exception exception); + +#if NET + [GeneratedRegex(@"[\s\.]+")] + private static partial Regex WhitespaceAndPeriods(); +#else + private static Regex WhitespaceAndPeriods() => s_whitespaceAndPeriods; + private static readonly Regex s_whitespaceAndPeriods = new(@"[\s\.]+", RegexOptions.Compiled); +#endif } diff --git a/src/ModelContextProtocol.Core/Diagnostics.cs b/src/ModelContextProtocol.Core/Diagnostics.cs index 308d07c5a..284d9088e 100644 --- a/src/ModelContextProtocol.Core/Diagnostics.cs +++ b/src/ModelContextProtocol.Core/Diagnostics.cs @@ -93,9 +93,9 @@ private static void InjectContext(object? message, string key, string value) { if (jsonObject["_meta"] is not JsonObject meta) { - meta = new JsonObject(); - jsonObject["_meta"] = meta; + jsonObject["_meta"] = meta = []; } + meta[key] = value; } } diff --git a/src/ModelContextProtocol.Core/McpSessionHandler.cs b/src/ModelContextProtocol.Core/McpSessionHandler.cs index a899f3d8e..fcd7980d9 100644 --- a/src/ModelContextProtocol.Core/McpSessionHandler.cs +++ b/src/ModelContextProtocol.Core/McpSessionHandler.cs @@ -405,7 +405,7 @@ public async Task SendRequestAsync(JsonRpcRequest request, Canc long? startingTimestamp = durationMetric.Enabled ? Stopwatch.GetTimestamp() : null; using Activity? activity = Diagnostics.ShouldInstrumentMessage(request) ? - Diagnostics.ActivitySource.StartActivity(CreateActivityName(method), ActivityKind.Client) : + Diagnostics.ActivitySource.StartActivity(McpSessionHandler.CreateActivityName(method), ActivityKind.Client) : null; // Set request ID @@ -501,7 +501,7 @@ public async Task SendMessageAsync(JsonRpcMessage message, CancellationToken can long? startingTimestamp = durationMetric.Enabled ? Stopwatch.GetTimestamp() : null; using Activity? activity = Diagnostics.ShouldInstrumentMessage(message) ? - Diagnostics.ActivitySource.StartActivity(CreateActivityName(method), ActivityKind.Client) : + Diagnostics.ActivitySource.StartActivity(McpSessionHandler.CreateActivityName(method), ActivityKind.Client) : null; TagList tags = default; @@ -567,7 +567,7 @@ private Task SendToRelatedTransportAsync(JsonRpcMessage message, CancellationTok } } - private string CreateActivityName(string method) => method; + private static string CreateActivityName(string method) => method; private static string GetMethodName(JsonRpcMessage message) => message switch diff --git a/src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj b/src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj index 07a5ec1b0..d39c008eb 100644 --- a/src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj +++ b/src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;netstandard2.0 + net10.0;net9.0;net8.0;netstandard2.0 true true ModelContextProtocol.Core @@ -27,16 +27,20 @@ - - + + + + + + + - diff --git a/src/ModelContextProtocol.Core/NotificationHandlers.cs b/src/ModelContextProtocol.Core/NotificationHandlers.cs index 4b9520730..da09c75e8 100644 --- a/src/ModelContextProtocol.Core/NotificationHandlers.cs +++ b/src/ModelContextProtocol.Core/NotificationHandlers.cs @@ -240,14 +240,8 @@ public async ValueTask DisposeAsync() // to point past this one. Importantly, we do not modify this node's Next or Prev. // We want to ensure that an enumeration through all of the registrations can still // progress through this one. - if (Prev is not null) - { - Prev.Next = Next; - } - if (Next is not null) - { - Next.Prev = Prev; - } + Prev?.Next = Next; + Next?.Prev = Prev; // Decrement the ref count. In the common case, there's no in-flight invocation for // this handler. However, in the uncommon case that there is, we need to wait for diff --git a/src/ModelContextProtocol.Core/Protocol/ProgressToken.cs b/src/ModelContextProtocol.Core/Protocol/ProgressToken.cs index f980bdf6f..bdb35f85b 100644 --- a/src/ModelContextProtocol.Core/Protocol/ProgressToken.cs +++ b/src/ModelContextProtocol.Core/Protocol/ProgressToken.cs @@ -11,15 +11,12 @@ namespace ModelContextProtocol.Protocol; [JsonConverter(typeof(Converter))] public readonly struct ProgressToken : IEquatable { - /// The token, either a string or a boxed long or null. - private readonly object? _token; - /// Initializes a new instance of the with a specified value. /// The required ID value. public ProgressToken(string value) { Throw.IfNull(value); - _token = value; + Token = value; } /// Initializes a new instance of the with a specified value. @@ -27,27 +24,27 @@ public ProgressToken(string value) public ProgressToken(long value) { // Box the long. Progress tokens are almost always strings in practice, so this should be rare. - _token = value; + Token = value; } /// Gets the underlying object for this token. /// This will either be a , a boxed , or . - public object? Token => _token; + public object? Token { get; } /// public override string? ToString() => - _token is string stringValue ? stringValue : - _token is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) : + Token is string stringValue ? stringValue : + Token is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) : null; /// - public bool Equals(ProgressToken other) => Equals(_token, other._token); + public bool Equals(ProgressToken other) => Equals(Token, other.Token); /// public override bool Equals(object? obj) => obj is ProgressToken other && Equals(other); /// - public override int GetHashCode() => _token?.GetHashCode() ?? 0; + public override int GetHashCode() => Token?.GetHashCode() ?? 0; /// public static bool operator ==(ProgressToken left, ProgressToken right) => left.Equals(right); @@ -77,7 +74,7 @@ public override void Write(Utf8JsonWriter writer, ProgressToken value, JsonSeria { Throw.IfNull(writer); - switch (value._token) + switch (value.Token) { case string str: writer.WriteStringValue(str); diff --git a/src/ModelContextProtocol.Core/Protocol/RequestId.cs b/src/ModelContextProtocol.Core/Protocol/RequestId.cs index 8d445deb8..39abe5abc 100644 --- a/src/ModelContextProtocol.Core/Protocol/RequestId.cs +++ b/src/ModelContextProtocol.Core/Protocol/RequestId.cs @@ -11,15 +11,12 @@ namespace ModelContextProtocol.Protocol; [JsonConverter(typeof(Converter))] public readonly struct RequestId : IEquatable { - /// The id, either a string or a boxed long or null. - private readonly object? _id; - /// Initializes a new instance of the with a specified value. /// The required ID value. public RequestId(string value) { Throw.IfNull(value); - _id = value; + Id = value; } /// Initializes a new instance of the with a specified value. @@ -27,27 +24,27 @@ public RequestId(string value) public RequestId(long value) { // Box the long. Request IDs are almost always strings in practice, so this should be rare. - _id = value; + Id = value; } /// Gets the underlying object for this id. /// This will either be a , a boxed , or . - public object? Id => _id; + public object? Id { get; } /// public override string ToString() => - _id is string stringValue ? stringValue : - _id is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) : + Id is string stringValue ? stringValue : + Id is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) : string.Empty; /// - public bool Equals(RequestId other) => Equals(_id, other._id); + public bool Equals(RequestId other) => Equals(Id, other.Id); /// public override bool Equals(object? obj) => obj is RequestId other && Equals(other); /// - public override int GetHashCode() => _id?.GetHashCode() ?? 0; + public override int GetHashCode() => Id?.GetHashCode() ?? 0; /// public static bool operator ==(RequestId left, RequestId right) => left.Equals(right); @@ -77,7 +74,7 @@ public override void Write(Utf8JsonWriter writer, RequestId value, JsonSerialize { Throw.IfNull(writer); - switch (value._id) + switch (value.Id) { case string str: writer.WriteStringValue(str); diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs index dadd876bb..720c37521 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs @@ -59,7 +59,7 @@ internal sealed class AIFunctionMcpServerPrompt : McpServerPrompt return Create( AIFunctionFactory.Create(method, args => { - Debug.Assert(args.Services is RequestServiceProvider, $"The service provider should be a {nameof(RequestServiceProvider)} for this method to work correctly."); + Debug.Assert(args.Services is RequestServiceProvider, $"The service provider should be a {nameof(RequestServiceProvider<>)} for this method to work correctly."); return createTargetFunc(((RequestServiceProvider)args.Services!).Request); }, CreateAIFunctionFactoryOptions(method, options)), options); diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs index 350f0d9b2..5746a7dff 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs @@ -67,7 +67,7 @@ internal sealed class AIFunctionMcpServerResource : McpServerResource return Create( AIFunctionFactory.Create(method, args => { - Debug.Assert(args.Services is RequestServiceProvider, $"The service provider should be a {nameof(RequestServiceProvider)} for this method to work correctly."); + Debug.Assert(args.Services is RequestServiceProvider, $"The service provider should be a {nameof(RequestServiceProvider<>)} for this method to work correctly."); return createTargetFunc(((RequestServiceProvider)args.Services!).Request); }, CreateAIFunctionFactoryOptions(method, options)), options); diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs index 91fbb3d6a..aa50046f9 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs @@ -63,7 +63,7 @@ internal sealed partial class AIFunctionMcpServerTool : McpServerTool return Create( AIFunctionFactory.Create(method, args => { - Debug.Assert(args.Services is RequestServiceProvider, $"The service provider should be a {nameof(RequestServiceProvider)} for this method to work correctly."); + Debug.Assert(args.Services is RequestServiceProvider, $"The service provider should be a {nameof(RequestServiceProvider<>)} for this method to work correctly."); return createTargetFunc(((RequestServiceProvider)args.Services!).Request); }, CreateAIFunctionFactoryOptions(method, options)), options); diff --git a/src/ModelContextProtocol.Core/Server/DestinationBoundMcpServer.cs b/src/ModelContextProtocol.Core/Server/DestinationBoundMcpServer.cs index bbbc45dcc..784e0f9a6 100644 --- a/src/ModelContextProtocol.Core/Server/DestinationBoundMcpServer.cs +++ b/src/ModelContextProtocol.Core/Server/DestinationBoundMcpServer.cs @@ -27,8 +27,11 @@ public override Task SendMessageAsync(JsonRpcMessage message, CancellationToken throw new ArgumentException("Only transports can provide a JsonRpcMessageContext."); } - message.Context = new JsonRpcMessageContext(); - message.Context.RelatedTransport = transport; + message.Context = new() + { + RelatedTransport = transport + }; + return server.SendMessageAsync(message, cancellationToken); } @@ -39,8 +42,11 @@ public override Task SendRequestAsync(JsonRpcRequest request, C throw new ArgumentException("Only transports can provide a JsonRpcMessageContext."); } - request.Context = new JsonRpcMessageContext(); - request.Context.RelatedTransport = transport; + request.Context = new() + { + RelatedTransport = transport + }; + return server.SendRequestAsync(request, cancellationToken); } } diff --git a/src/ModelContextProtocol.Core/Server/McpServer.Methods.cs b/src/ModelContextProtocol.Core/Server/McpServer.Methods.cs index 0d255c5b0..a24918bd9 100644 --- a/src/ModelContextProtocol.Core/Server/McpServer.Methods.cs +++ b/src/ModelContextProtocol.Core/Server/McpServer.Methods.cs @@ -341,13 +341,9 @@ private static ElicitRequestParams.PrimitiveSchemaDefinition CreatePrimitiveSche throw new McpProtocolException(error); } - var primitiveSchemaDefinition = - jsonElement.Deserialize(McpJsonUtilities.JsonContext.Default.PrimitiveSchemaDefinition); - - if (primitiveSchemaDefinition is null) + return + jsonElement.Deserialize(McpJsonUtilities.JsonContext.Default.PrimitiveSchemaDefinition) ?? throw new McpProtocolException($"Type '{type.FullName}' is not a supported property type for elicitation requests."); - - return primitiveSchemaDefinition; } /// @@ -452,11 +448,9 @@ private void ThrowIfElicitationUnsupported() } /// Provides an implementation that's implemented via client sampling. - private sealed class SamplingChatClient : IChatClient + private sealed class SamplingChatClient(McpServer server) : IChatClient { - private readonly McpServer _server; - - public SamplingChatClient(McpServer server) => _server = server; + private readonly McpServer _server = server; /// public Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken cancellationToken = default) => @@ -493,11 +487,9 @@ void IDisposable.Dispose() { } // nop /// Provides an implementation for creating loggers /// that send logging message notifications to the client for logged messages. /// - private sealed class ClientLoggerProvider : ILoggerProvider + private sealed class ClientLoggerProvider(McpServer server) : ILoggerProvider { - private readonly McpServer _server; - - public ClientLoggerProvider(McpServer server) => _server = server; + private readonly McpServer _server = server; /// public ILogger CreateLogger(string categoryName) @@ -510,16 +502,10 @@ public ILogger CreateLogger(string categoryName) /// void IDisposable.Dispose() { } - private sealed class ClientLogger : ILogger + private sealed class ClientLogger(McpServer server, string categoryName) : ILogger { - private readonly McpServer _server; - private readonly string _categoryName; - - public ClientLogger(McpServer server, string categoryName) - { - _server = server; - _categoryName = categoryName; - } + private readonly McpServer _server = server; + private readonly string _categoryName = categoryName; /// public IDisposable? BeginScope(TState state) where TState : notnull => diff --git a/src/ModelContextProtocol.Core/Server/McpServerFilters.cs b/src/ModelContextProtocol.Core/Server/McpServerFilters.cs index e38421bc1..d68b349d2 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerFilters.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerFilters.cs @@ -26,7 +26,7 @@ public sealed class McpServerFilters /// Tools from both sources will be combined when returning results to clients. /// /// - public List> ListToolsFilters { get; } = new(); + public List> ListToolsFilters { get; } = []; /// /// Gets the filters for the call tool handler pipeline. @@ -36,7 +36,7 @@ public sealed class McpServerFilters /// The filters can modify, log, or perform additional operations on requests and responses for /// requests. The handler should implement logic to execute the requested tool and return appropriate results. /// - public List> CallToolFilters { get; } = new(); + public List> CallToolFilters { get; } = []; /// /// Gets the filters for the list prompts handler pipeline. @@ -53,7 +53,7 @@ public sealed class McpServerFilters /// Prompts from both sources will be combined when returning results to clients. /// /// - public List> ListPromptsFilters { get; } = new(); + public List> ListPromptsFilters { get; } = []; /// /// Gets the filters for the get prompt handler pipeline. @@ -63,7 +63,7 @@ public sealed class McpServerFilters /// The filters can modify, log, or perform additional operations on requests and responses for /// requests. The handler should implement logic to fetch or generate the requested prompt and return appropriate results. /// - public List> GetPromptFilters { get; } = new(); + public List> GetPromptFilters { get; } = []; /// /// Gets the filters for the list resource templates handler pipeline. @@ -74,7 +74,7 @@ public sealed class McpServerFilters /// requests. It supports pagination through the cursor mechanism, /// where the client can make repeated calls with the cursor returned by the previous call to retrieve more resource templates. /// - public List> ListResourceTemplatesFilters { get; } = new(); + public List> ListResourceTemplatesFilters { get; } = []; /// /// Gets the filters for the list resources handler pipeline. @@ -85,7 +85,7 @@ public sealed class McpServerFilters /// requests. It supports pagination through the cursor mechanism, /// where the client can make repeated calls with the cursor returned by the previous call to retrieve more resources. /// - public List> ListResourcesFilters { get; } = new(); + public List> ListResourcesFilters { get; } = []; /// /// Gets the filters for the read resource handler pipeline. @@ -95,7 +95,7 @@ public sealed class McpServerFilters /// The filters can modify, log, or perform additional operations on requests and responses for /// requests. The handler should implement logic to locate and retrieve the requested resource. /// - public List> ReadResourceFilters { get; } = new(); + public List> ReadResourceFilters { get; } = []; /// /// Gets the filters for the complete handler pipeline. @@ -106,7 +106,7 @@ public sealed class McpServerFilters /// requests. The handler processes auto-completion requests, returning a list of suggestions based on the /// reference type and current argument value. /// - public List> CompleteFilters { get; } = new(); + public List> CompleteFilters { get; } = []; /// /// Gets the filters for the subscribe to resources handler pipeline. @@ -123,7 +123,7 @@ public sealed class McpServerFilters /// whenever a relevant resource is created, updated, or deleted. /// /// - public List> SubscribeToResourcesFilters { get; } = new(); + public List> SubscribeToResourcesFilters { get; } = []; /// /// Gets the filters for the unsubscribe from resources handler pipeline. @@ -140,7 +140,7 @@ public sealed class McpServerFilters /// to the client for the specified resources. /// /// - public List> UnsubscribeFromResourcesFilters { get; } = new(); + public List> UnsubscribeFromResourcesFilters { get; } = []; /// /// Gets the filters for the set logging level handler pipeline. @@ -157,5 +157,5 @@ public sealed class McpServerFilters /// at or above the specified level to the client as notifications/message notifications. /// /// - public List> SetLoggingLevelFilters { get; } = new(); + public List> SetLoggingLevelFilters { get; } = []; } diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs index 8e264741b..2646883b7 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs @@ -207,12 +207,9 @@ private void ConfigureInitialize(McpServerOptions options) // Otherwise, try to use whatever the client requested as long as it's supported. // If it's not supported, fall back to the latest supported version. string? protocolVersion = options.ProtocolVersion; - if (protocolVersion is null) - { - protocolVersion = request?.ProtocolVersion is string clientProtocolVersion && McpSessionHandler.SupportedProtocolVersions.Contains(clientProtocolVersion) ? - clientProtocolVersion : - McpSessionHandler.LatestProtocolVersion; - } + protocolVersion ??= request?.ProtocolVersion is string clientProtocolVersion && McpSessionHandler.SupportedProtocolVersions.Contains(clientProtocolVersion) ? + clientProtocolVersion : + McpSessionHandler.LatestProtocolVersion; _negotiatedProtocolVersion = protocolVersion; diff --git a/src/ModelContextProtocol.Core/Server/McpServerOptions.cs b/src/ModelContextProtocol.Core/Server/McpServerOptions.cs index 833c852e3..618e87d58 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerOptions.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerOptions.cs @@ -7,8 +7,6 @@ namespace ModelContextProtocol.Server; /// public sealed class McpServerOptions { - private McpServerHandlers? _handlers; - /// /// Gets or sets information about this server implementation, including its name and version. /// @@ -97,11 +95,11 @@ public sealed class McpServerOptions /// public McpServerHandlers Handlers { - get => _handlers ??= new(); + get => field ??= new(); set { Throw.IfNull(value); - _handlers = value; + field = value; } } diff --git a/src/ModelContextProtocol.Core/Server/McpServerPromptCreateOptions.cs b/src/ModelContextProtocol.Core/Server/McpServerPromptCreateOptions.cs index 146c0e063..434ed4052 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerPromptCreateOptions.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerPromptCreateOptions.cs @@ -90,7 +90,7 @@ public sealed class McpServerPromptCreateOptions /// Creates a shallow clone of the current instance. /// internal McpServerPromptCreateOptions Clone() => - new McpServerPromptCreateOptions + new() { Services = Services, Name = Name, diff --git a/src/ModelContextProtocol.Core/Server/McpServerResourceCreateOptions.cs b/src/ModelContextProtocol.Core/Server/McpServerResourceCreateOptions.cs index c2ec444cd..c519828a0 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerResourceCreateOptions.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerResourceCreateOptions.cs @@ -105,7 +105,7 @@ public sealed class McpServerResourceCreateOptions /// Creates a shallow clone of the current instance. /// internal McpServerResourceCreateOptions Clone() => - new McpServerResourceCreateOptions + new() { Services = Services, UriTemplate = UriTemplate, diff --git a/src/ModelContextProtocol.Core/Server/McpServerToolCreateOptions.cs b/src/ModelContextProtocol.Core/Server/McpServerToolCreateOptions.cs index cb4205be1..73f76bca7 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerToolCreateOptions.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerToolCreateOptions.cs @@ -176,7 +176,7 @@ public sealed class McpServerToolCreateOptions /// Creates a shallow clone of the current instance. /// internal McpServerToolCreateOptions Clone() => - new McpServerToolCreateOptions + new() { Services = Services, Name = Name, diff --git a/src/ModelContextProtocol.Core/Server/RequestContext.cs b/src/ModelContextProtocol.Core/Server/RequestContext.cs index f75cea80b..1240e37f6 100644 --- a/src/ModelContextProtocol.Core/Server/RequestContext.cs +++ b/src/ModelContextProtocol.Core/Server/RequestContext.cs @@ -17,8 +17,6 @@ public sealed class RequestContext /// The server with which this instance is associated. private McpServer _server; - private IDictionary? _items; - /// /// Initializes a new instance of the class with the specified server and JSON-RPC request. /// @@ -51,14 +49,8 @@ public McpServer Server /// public IDictionary Items { - get - { - return _items ??= new Dictionary(); - } - set - { - _items = value; - } + get => field ??= new Dictionary(); + set => field = value; } /// Gets or sets the services associated with this request. diff --git a/src/ModelContextProtocol.Core/UriTemplate.cs b/src/ModelContextProtocol.Core/UriTemplate.cs index a822b6f2a..27e2f0d8d 100644 --- a/src/ModelContextProtocol.Core/UriTemplate.cs +++ b/src/ModelContextProtocol.Core/UriTemplate.cs @@ -243,7 +243,7 @@ public static string FormatUri(string uriTemplate, IReadOnlyDictionary.Empty; + expression = []; } else { @@ -373,7 +373,7 @@ value as string ?? return builder.ToStringAndClear(); } - private static void AppendJoin(ref DefaultInterpolatedStringHandler builder, string separator, IList values) + private static void AppendJoin(ref DefaultInterpolatedStringHandler builder, string separator, List values) { int count = values.Count; if (count > 0) @@ -441,8 +441,8 @@ static void AppendHex(ref DefaultInterpolatedStringHandler builder, char c) else { #if NET - Span utf8 = stackalloc byte[Encoding.UTF8.GetMaxByteCount(1)]; - foreach (byte b in utf8.Slice(0, new Rune(c).EncodeToUtf8(utf8))) + Span utf8 = stackalloc byte[Encoding.UTF8.GetMaxByteCount(1)]; + foreach (byte b in utf8.Slice(0, new Rune(c).EncodeToUtf8(utf8))) #else foreach (byte b in Encoding.UTF8.GetBytes([c])) #endif diff --git a/src/ModelContextProtocol/ModelContextProtocol.csproj b/src/ModelContextProtocol/ModelContextProtocol.csproj index 963ba0fed..b69108ab2 100644 --- a/src/ModelContextProtocol/ModelContextProtocol.csproj +++ b/src/ModelContextProtocol/ModelContextProtocol.csproj @@ -1,7 +1,7 @@  - net9.0;net8.0;netstandard2.0 + net10.0;net9.0;net8.0;netstandard2.0 true true ModelContextProtocol diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs index 073b2fd18..bbe1b43af 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs @@ -448,7 +448,7 @@ private async Task StartServerWithoutAuthFilters(Action new ClaimsPrincipal(new ClaimsIdentity( + => new(new ClaimsIdentity( [new Claim("name", name), new Claim(ClaimTypes.NameIdentifier, name), .. roles.Select(role => new Claim("role", role))], "TestAuthType", "name", "role")); diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs index 166d492f2..d3700f57f 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs @@ -241,7 +241,7 @@ public async Task Server_ShutsDownQuickly_WhenClientIsConnected() } private ClaimsPrincipal CreateUser(string name) - => new ClaimsPrincipal(new ClaimsIdentity( + => new(new ClaimsIdentity( [new Claim("name", name), new Claim(ClaimTypes.NameIdentifier, name)], "TestAuthType", "name", "role")); diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpServerConformanceTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpServerConformanceTests.cs index 5cc7f74d8..3f45d52d4 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpServerConformanceTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpServerConformanceTests.cs @@ -556,7 +556,7 @@ public async Task McpServer_UsedOutOfScope_CanSendNotifications() Assert.Equal(NotificationMethods.ResourceUpdatedNotification, notification.Method); } - private static StringContent JsonContent(string json) => new StringContent(json, Encoding.UTF8, "application/json"); + private static StringContent JsonContent(string json) => new(json, Encoding.UTF8, "application/json"); private static JsonTypeInfo GetJsonTypeInfo() => (JsonTypeInfo)McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(T)); private static T AssertType(JsonNode? jsonNode) diff --git a/tests/ModelContextProtocol.TestOAuthServer/AuthorizationServerMetadata.cs b/tests/ModelContextProtocol.TestOAuthServer/AuthorizationServerMetadata.cs index 32472a883..a192bbf60 100644 --- a/tests/ModelContextProtocol.TestOAuthServer/AuthorizationServerMetadata.cs +++ b/tests/ModelContextProtocol.TestOAuthServer/AuthorizationServerMetadata.cs @@ -29,7 +29,7 @@ internal sealed class AuthorizationServerMetadata /// Gets the introspection endpoint URL. /// [JsonPropertyName("introspection_endpoint")] - public Uri? IntrospectionEndpoint => new Uri($"{Issuer}/introspect"); + public Uri? IntrospectionEndpoint => new($"{Issuer}/introspect"); /// /// Gets or sets the response types supported by this server. diff --git a/tests/ModelContextProtocol.TestSseServer/Program.cs b/tests/ModelContextProtocol.TestSseServer/Program.cs index e2eb3435f..9eef66400 100644 --- a/tests/ModelContextProtocol.TestSseServer/Program.cs +++ b/tests/ModelContextProtocol.TestSseServer/Program.cs @@ -56,8 +56,8 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st } #endregion - List resources = new(); - List resourceContents = new(); + List resources = []; + List resourceContents = []; for (int i = 0; i < 100; ++i) { string uri = $"test://static/resource/{i + 1}"; @@ -319,7 +319,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st { throw new McpProtocolException("Missing required parameter 'name'", McpErrorCode.InvalidParams); } - List messages = new(); + List messages = []; if (request.Params.Name == "simple_prompt") { messages.Add(new PromptMessage diff --git a/tests/ModelContextProtocol.Tests/DiagnosticTests.cs b/tests/ModelContextProtocol.Tests/DiagnosticTests.cs index b0e7b6d07..55a3b4932 100644 --- a/tests/ModelContextProtocol.Tests/DiagnosticTests.cs +++ b/tests/ModelContextProtocol.Tests/DiagnosticTests.cs @@ -88,7 +88,7 @@ await RunConnected(async (client, server) => { await client.CallToolAsync("Throw", cancellationToken: TestContext.Current.CancellationToken); await Assert.ThrowsAsync(async () => await client.CallToolAsync("does-not-exist", cancellationToken: TestContext.Current.CancellationToken)); - }, new List()); + }, []); } Assert.NotEmpty(activities); diff --git a/tests/ModelContextProtocol.Tests/Protocol/IconTests.cs b/tests/ModelContextProtocol.Tests/Protocol/IconTests.cs index ff248ec17..7711ee6ca 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/IconTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/IconTests.cs @@ -13,7 +13,7 @@ public static void Icon_SerializationRoundTrip_PreservesAllProperties() { Source = "https://example.com/icon.png", MimeType = "image/png", - Sizes = new List { "48x48" }, + Sizes = ["48x48"], Theme = "light" }; @@ -61,7 +61,7 @@ public static void Icon_HasCorrectJsonPropertyNames() { Source = "https://example.com/icon.svg", MimeType = "image/svg+xml", - Sizes = new List { "any" }, + Sizes = ["any"], Theme = "dark" }; diff --git a/tests/ModelContextProtocol.Tests/Protocol/ImplementationTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ImplementationTests.cs index ff938eff9..e3fae24f4 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/ImplementationTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/ImplementationTests.cs @@ -16,8 +16,8 @@ public static void Implementation_SerializationRoundTrip_PreservesAllProperties( Version = "1.0.0", Icons = [ - new() { Source = "https://example.com/icon.png", MimeType = "image/png", Sizes = new List { "48x48" } }, - new() { Source = "https://example.com/icon.svg", MimeType = "image/svg+xml", Sizes = new List { "any" } } + new() { Source = "https://example.com/icon.png", MimeType = "image/png", Sizes = ["48x48"] }, + new() { Source = "https://example.com/icon.svg", MimeType = "image/svg+xml", Sizes = ["any"] } ], WebsiteUrl = "https://example.com" }; diff --git a/tests/ModelContextProtocol.Tests/Protocol/PromptTests.cs b/tests/ModelContextProtocol.Tests/Protocol/PromptTests.cs index e73ee4cf5..d3acf782a 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/PromptTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/PromptTests.cs @@ -16,7 +16,7 @@ public static void Prompt_SerializationRoundTrip_PreservesAllProperties() Description = "Review the provided code", Icons = [ - new() { Source = "https://example.com/review-icon.svg", MimeType = "image/svg+xml", Sizes = new List { "any" } } + new() { Source = "https://example.com/review-icon.svg", MimeType = "image/svg+xml", Sizes = ["any"] } ], Arguments = [ diff --git a/tests/ModelContextProtocol.Tests/Protocol/ResourceTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ResourceTests.cs index e0e71a036..59c076a69 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/ResourceTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/ResourceTests.cs @@ -19,7 +19,7 @@ public static void Resource_SerializationRoundTrip_PreservesAllProperties() Size = 1024, Icons = [ - new() { Source = "https://example.com/pdf-icon.png", MimeType = "image/png", Sizes = new List { "32x32" } } + new() { Source = "https://example.com/pdf-icon.png", MimeType = "image/png", Sizes = ["32x32"] } ], Annotations = new Annotations { Audience = [Role.User] } }; @@ -86,7 +86,7 @@ public static void Resource_HasCorrectJsonPropertyNames() Description = "A test resource", MimeType = "text/plain", Size = 512, - Icons = new List { new() { Source = "https://example.com/icon.svg" } }, + Icons = [new() { Source = "https://example.com/icon.svg" }], Annotations = new Annotations { Audience = [Role.User] } }; diff --git a/tests/ModelContextProtocol.Tests/Protocol/ToolTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ToolTests.cs index 630ced49c..75e837cc2 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/ToolTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/ToolTests.cs @@ -16,7 +16,7 @@ public static void Tool_SerializationRoundTrip_PreservesAllProperties() Description = "Get current weather information", Icons = [ - new() { Source = "https://example.com/weather.png", MimeType = "image/png", Sizes = new List { "48x48" } } + new() { Source = "https://example.com/weather.png", MimeType = "image/png", Sizes = ["48x48"] } ], Annotations = new ToolAnnotations { diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs index 1cb7548db..b463514f9 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerPromptTests.cs @@ -498,7 +498,7 @@ public void SupportsIconsInCreateOptions() { var icons = new List { - new() { Source = "https://example.com/prompt-icon.png", MimeType = "image/png", Sizes = new List { "48x48" } } + new() { Source = "https://example.com/prompt-icon.png", MimeType = "image/png", Sizes = ["48x48"] } }; McpServerPrompt prompt = McpServerPrompt.Create(() => "test prompt", new McpServerPromptCreateOptions diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs index c52778df1..135633b82 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs @@ -307,7 +307,7 @@ public async Task ResourceCollection_UsesCaseInsensitiveHostLookup() { McpServerResource t1 = McpServerResource.Create(() => "resource", new() { UriTemplate = "resource://MyCoolResource" }); McpServerResource t2 = McpServerResource.Create(() => "resource", new() { UriTemplate = "resource://MyCoolResource2" }); - McpServerResourceCollection collection = new() { t1, t2 }; + McpServerResourceCollection collection = [t1, t2]; Assert.True(collection.TryGetPrimitive("resource://mycoolresource", out McpServerResource? result)); Assert.Same(t1, result); } @@ -537,7 +537,7 @@ public async Task CanReturnReadResult() McpServerResource resource = McpServerResource.Create((McpServer server) => { Assert.Same(mockServer.Object, server); - return new ReadResourceResult { Contents = new List { new TextResourceContents { Text = "hello" } } }; + return new ReadResourceResult { Contents = [new TextResourceContents { Text = "hello" }] }; }, new() { Name = "Test" }); var result = await resource.ReadAsync( new RequestContext(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } }, @@ -682,7 +682,7 @@ public void SupportsIconsInResourceCreateOptions() { var icons = new List { - new() { Source = "https://example.com/resource-icon.png", MimeType = "image/png", Sizes = new List { "32x32" } } + new() { Source = "https://example.com/resource-icon.png", MimeType = "image/png", Sizes = ["32x32"] } }; McpServerResource resource = McpServerResource.Create(() => "test content", new McpServerResourceCreateOptions diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs index 111d13430..4a9f76ae7 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs @@ -413,7 +413,7 @@ public async Task CanReturnCallToolResult() { CallToolResult response = new() { - Content = new List { new TextContentBlock { Text = "text" }, new ImageContentBlock { Data = "1234", MimeType = "image/png" } } + Content = [new TextContentBlock { Text = "text" }, new ImageContentBlock { Data = "1234", MimeType = "image/png" }] }; Mock mockServer = new(); @@ -683,8 +683,8 @@ public void SupportsIconsInCreateOptions() { var icons = new List { - new() { Source = "https://example.com/icon.png", MimeType = "image/png", Sizes = new List { "48x48" } }, - new() { Source = "https://example.com/icon.svg", MimeType = "image/svg+xml", Sizes = new List { "any" } } + new() { Source = "https://example.com/icon.png", MimeType = "image/png", Sizes = ["48x48"] }, + new() { Source = "https://example.com/icon.svg", MimeType = "image/svg+xml", Sizes = ["any"] } }; McpServerTool tool = McpServerTool.Create(() => "test", new McpServerToolCreateOptions