From 3c299f366d5248b3e3d76ef449459f501ef0e8c0 Mon Sep 17 00:00:00 2001 From: Damien Girard Date: Tue, 17 Feb 2026 14:12:23 +0200 Subject: [PATCH 1/3] Downgrade Microsoft.Extensions.* to 8.x for net8.0 TFM Consumers running on .NET 8 runtime (including PowerShell) hit conflicts with Microsoft.Extensions.* 10.x dependencies. Condition package versions so the net8.0 build uses 8.x versions of Microsoft.Extensions.* packages while other TFMs continue using 10.x. Key changes: - Split shared product and testing M.E.* deps into net8.0/non-net8.0 groups - M.E.AI/AI.Abstractions use 9.10.2 for net8.0 (latest 9.x with 8.x transitive deps) - Add explicit System.Text.Json 10.x dep for net8.0 (no longer transitive from M.E.*) - Downgrade Serilog.Extensions.Hosting/Logging to 8.0.0 for net8.0 - Add ILogger field in StreamableHttpPostTransport for 8.x LoggerMessage generator - Conditional-compile InstrumentAdvice usage (not in net8.0 DiagnosticSource) - Exclude M.E.AI.OpenAI from net8.0 test builds (requires M.E.AI 10.x) - Move ChatWithTools sample to net9.0 (depends on M.E.AI.OpenAI) Co-Authored-By: Claude Opus 4.6 --- Directory.Packages.props | 50 +++++++++++++++---- .../AspNetCoreMcpServer.csproj | 2 +- samples/ChatWithTools/ChatWithTools.csproj | 2 +- src/ModelContextProtocol.Core/Diagnostics.cs | 4 ++ .../ModelContextProtocol.Core.csproj | 5 ++ .../Server/StreamableHttpPostTransport.cs | 1 + ...delContextProtocol.AspNetCore.Tests.csproj | 2 +- .../ClientIntegrationTests.cs | 6 +++ .../ModelContextProtocol.Tests.csproj | 2 +- 9 files changed, 59 insertions(+), 15 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 3f5540f9d..46180d362 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,10 +5,11 @@ 9.0.11 10.0.3 10.3.0 + 9.10.2 - - + + @@ -17,6 +18,16 @@ + + + + + + + + + + @@ -34,6 +45,7 @@ + @@ -67,13 +79,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - - - - @@ -82,8 +87,10 @@ - - + + + + @@ -94,4 +101,25 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AspNetCoreMcpServer/AspNetCoreMcpServer.csproj b/samples/AspNetCoreMcpServer/AspNetCoreMcpServer.csproj index 59ab49828..39ea74a97 100644 --- a/samples/AspNetCoreMcpServer/AspNetCoreMcpServer.csproj +++ b/samples/AspNetCoreMcpServer/AspNetCoreMcpServer.csproj @@ -1,7 +1,7 @@ - net9.0 + net8.0 enable enable true diff --git a/samples/ChatWithTools/ChatWithTools.csproj b/samples/ChatWithTools/ChatWithTools.csproj index 3723185fe..901e1ad7d 100644 --- a/samples/ChatWithTools/ChatWithTools.csproj +++ b/samples/ChatWithTools/ChatWithTools.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable enable + + + + diff --git a/src/ModelContextProtocol.Core/Server/StreamableHttpPostTransport.cs b/src/ModelContextProtocol.Core/Server/StreamableHttpPostTransport.cs index 7f399bab3..6a69cf440 100644 --- a/src/ModelContextProtocol.Core/Server/StreamableHttpPostTransport.cs +++ b/src/ModelContextProtocol.Core/Server/StreamableHttpPostTransport.cs @@ -17,6 +17,7 @@ internal sealed partial class StreamableHttpPostTransport( CancellationToken sessionCancellationToken, ILogger logger) : ITransport { + private readonly ILogger _logger = logger; private readonly SemaphoreSlim _messageLock = new(1, 1); private readonly TaskCompletionSource _httpResponseTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly SseEventWriter _httpSseWriter = new(responseStream); diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj b/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj index 384e8fcdd..38032f8e8 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj +++ b/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj @@ -33,7 +33,7 @@ - + diff --git a/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs b/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs index 018e12dbe..a048362ca 100644 --- a/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs +++ b/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs @@ -2,7 +2,9 @@ using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; using ModelContextProtocol.Tests.Utils; +#if !NET8_0 using OpenAI; +#endif using System.Text.Json; using System.Text.Json.Serialization; @@ -10,9 +12,11 @@ namespace ModelContextProtocol.Tests; public partial class ClientIntegrationTests : LoggedTest, IClassFixture { +#if !NET8_0 private static readonly string? s_openAIKey = Environment.GetEnvironmentVariable("AI:OpenAI:ApiKey"); public static bool NoOpenAIKeySet => string.IsNullOrWhiteSpace(s_openAIKey); +#endif private readonly ClientIntegrationTestFixture _fixture; @@ -492,6 +496,7 @@ public async Task CallTool_Stdio_MemoryServer() await client.DisposeAsync(); } +#if !NET8_0 [Fact(Skip = "Requires OpenAI API Key", SkipWhen = nameof(NoOpenAIKeySet))] public async Task ListToolsAsync_UsingEverythingServer_ToolsAreProperlyCalled() { @@ -547,6 +552,7 @@ public async Task SamplingViaChatClient_RequestResponseProperlyPropagated() Assert.Contains("LLM sampling result:", content.Text); Assert.Contains("Eiffel", content.Text); } +#endif [Theory] [MemberData(nameof(GetClients))] diff --git a/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj b/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj index 0985f4cd7..3968cbaf2 100644 --- a/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj +++ b/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj @@ -60,7 +60,7 @@ all - + From ebe64507179583cf13b46c951b013a664211fe33 Mon Sep 17 00:00:00 2001 From: Damien Girard Date: Tue, 17 Feb 2026 14:19:48 +0200 Subject: [PATCH 2/3] Add prerequisites section documenting .NET 8.0 support and System.Text.Json 10.x dependency Co-Authored-By: Claude Opus 4.6 --- README.md | 7 +++++++ src/ModelContextProtocol.Core/README.md | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index d282e9af3..06879025f 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,13 @@ For more information about MCP: - [Protocol Specification](https://modelcontextprotocol.io/specification/) - [GitHub Organization](https://github.com/modelcontextprotocol) +## Prerequisites + +The SDK targets .NET Standard 2.0, .NET 8.0, .NET 9.0, and .NET 10.0. When targeting .NET 8.0, the SDK uses 8.x versions of `Microsoft.Extensions.*` dependencies for runtime compatibility. + +> [!IMPORTANT] +> The SDK depends on `System.Text.Json` 10.x on all target frameworks, including .NET 8.0. If your application pins `System.Text.Json` to an 8.x version, you will need to allow the upgrade to 10.x for the SDK to function correctly. + ## Installation To get started, install the package from NuGet diff --git a/src/ModelContextProtocol.Core/README.md b/src/ModelContextProtocol.Core/README.md index 69913a150..1414a5263 100644 --- a/src/ModelContextProtocol.Core/README.md +++ b/src/ModelContextProtocol.Core/README.md @@ -17,6 +17,13 @@ For more information about MCP: - [Protocol Specification](https://modelcontextprotocol.io/specification/) - [GitHub Organization](https://github.com/modelcontextprotocol) +## Prerequisites + +The SDK targets .NET Standard 2.0, .NET 8.0, .NET 9.0, and .NET 10.0. When targeting .NET 8.0, the SDK uses 8.x versions of `Microsoft.Extensions.*` dependencies for runtime compatibility. + +> [!IMPORTANT] +> The SDK depends on `System.Text.Json` 10.x on all target frameworks, including .NET 8.0. If your application pins `System.Text.Json` to an 8.x version, you will need to allow the upgrade to 10.x for the SDK to function correctly. + ## Installation To get started, install the core package from NuGet From 02c595ace19a78b8109faf91c61fa1c843ded0c0 Mon Sep 17 00:00:00 2001 From: Damien Girard Date: Tue, 17 Feb 2026 19:30:04 +0200 Subject: [PATCH 3/3] Fix pre-existing test failures on Windows - Fix TestServer.exe path resolution by using full path instead of bare filename, which failed when cmd.exe wrapper resolved against repo root - Fix conformance test success detection to handle Node.js libuv assertion crash on Windows by checking stdout for "0 failed" as fallback Co-Authored-By: Claude Opus 4.6 --- .../ServerConformanceTests.cs | 15 ++++++++++++--- .../ClientIntegrationTestFixture.cs | 3 ++- .../Transport/StdioClientTransportTests.cs | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/ServerConformanceTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/ServerConformanceTests.cs index d2501456c..c00f8c117 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/ServerConformanceTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/ServerConformanceTests.cs @@ -173,10 +173,19 @@ public async Task RunPendingConformanceTest_ServerSsePolling() ); } + var stdOut = outputBuilder.ToString(); + var stdErr = errorBuilder.ToString(); + + // On Windows, the Node.js conformance runner can crash during shutdown due to a libuv assertion + // (UV_HANDLE_CLOSING), producing a non-zero exit code even when all tests pass. Fall back to + // checking the output for "0 failed" when the exit code is non-zero. + bool success = process.ExitCode == 0 || + (stdOut.Contains("0 failed") && !stdOut.Contains("FAILURE")); + return ( - Success: process.ExitCode == 0, - Output: outputBuilder.ToString(), - Error: errorBuilder.ToString() + Success: success, + Output: stdOut, + Error: stdErr ); } } diff --git a/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs b/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs index 049d72d60..faf83814d 100644 --- a/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs +++ b/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs @@ -27,8 +27,9 @@ public ClientIntegrationTestFixture() TestServerTransportOptions = new() { - Command = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "TestServer.exe" : PlatformDetection.IsMonoRuntime ? "mono" : "dotnet", + Command = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Path.Combine(AppContext.BaseDirectory, "TestServer.exe") : PlatformDetection.IsMonoRuntime ? "mono" : "dotnet", Name = "TestServer", + WorkingDirectory = AppContext.BaseDirectory, }; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) diff --git a/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs b/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs index c33ed7f72..6f1817f2f 100644 --- a/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs +++ b/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs @@ -111,7 +111,7 @@ public async Task EscapesCliArgumentsCorrectly(string? cliArgumentValue) Command = (PlatformDetection.IsMonoRuntime, PlatformDetection.IsWindows) switch { (true, _) => "mono", - (_, true) => "TestServer.exe", + (_, true) => Path.Combine(AppContext.BaseDirectory, "TestServer.exe"), _ => "dotnet", }, Arguments = (PlatformDetection.IsMonoRuntime, PlatformDetection.IsWindows) switch @@ -120,6 +120,7 @@ public async Task EscapesCliArgumentsCorrectly(string? cliArgumentValue) (_, true) => [cliArgument], _ => ["TestServer.dll", cliArgument], }, + WorkingDirectory = AppContext.BaseDirectory, }; var transport = new StdioClientTransport(options, LoggerFactory);