From 8b9e9993b1a4b452843439a205d74da0a269ee10 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:28:42 +0000 Subject: [PATCH 1/3] Initial plan From dcdba1055ba2877f36360955cb9f362d4ce46265 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:36:57 +0000 Subject: [PATCH 2/3] Fix race condition in StdioClientTransport on .NET Framework Add thread synchronization around Console.InputEncoding modification to prevent race conditions when multiple transports are created concurrently on .NET Framework. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../Client/StdioClientTransport.cs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs b/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs index f3e624159..9a35e61ca 100644 --- a/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs +++ b/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs @@ -25,6 +25,12 @@ namespace ModelContextProtocol.Client; /// public sealed partial class StdioClientTransport : IClientTransport { +#if !NET + // On .NET Framework, we need to synchronize access to Console.InputEncoding + // to prevent race conditions when multiple transports are created concurrently. + private static readonly object s_consoleEncodingLock = new(); +#endif + private readonly StdioClientTransportOptions _options; private readonly ILoggerFactory? _loggerFactory; @@ -156,18 +162,23 @@ public async Task ConnectAsync(CancellationToken cancellationToken = // up the encoding from Console.InputEncoding. As such, when not targeting .NET Core, // we temporarily change Console.InputEncoding to no-BOM UTF-8 around the Process.Start // call, to ensure it picks up the correct encoding. + // IMPORTANT: This must be synchronized to prevent race conditions when multiple + // transports are created concurrently. #if NET processStarted = process.Start(); #else - Encoding originalInputEncoding = Console.InputEncoding; - try - { - Console.InputEncoding = StreamClientSessionTransport.NoBomUtf8Encoding; - processStarted = process.Start(); - } - finally + lock (s_consoleEncodingLock) { - Console.InputEncoding = originalInputEncoding; + Encoding originalInputEncoding = Console.InputEncoding; + try + { + Console.InputEncoding = StreamClientSessionTransport.NoBomUtf8Encoding; + processStarted = process.Start(); + } + finally + { + Console.InputEncoding = originalInputEncoding; + } } #endif From 7fcdbaefca820c0e76bd76ec0a54b807fe4a96fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:53:09 +0000 Subject: [PATCH 3/3] Move IMPORTANT comment into else block per review feedback Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- src/ModelContextProtocol.Core/Client/StdioClientTransport.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs b/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs index 9a35e61ca..55483b643 100644 --- a/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs +++ b/src/ModelContextProtocol.Core/Client/StdioClientTransport.cs @@ -162,11 +162,11 @@ public async Task ConnectAsync(CancellationToken cancellationToken = // up the encoding from Console.InputEncoding. As such, when not targeting .NET Core, // we temporarily change Console.InputEncoding to no-BOM UTF-8 around the Process.Start // call, to ensure it picks up the correct encoding. - // IMPORTANT: This must be synchronized to prevent race conditions when multiple - // transports are created concurrently. #if NET processStarted = process.Start(); #else + // IMPORTANT: This must be synchronized to prevent race conditions when multiple + // transports are created concurrently. lock (s_consoleEncodingLock) { Encoding originalInputEncoding = Console.InputEncoding;