Skip to content

Commit 8ad61e5

Browse files
committed
Address feedback and CI failure
1 parent a698b02 commit 8ad61e5

3 files changed

Lines changed: 21 additions & 9 deletions

File tree

src/ModelContextProtocol.Core/Client/StdioClientSessionTransport.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,12 @@ public override async Task SendMessageAsync(JsonRpcMessage message, Cancellation
4848
protected override async ValueTask CleanupAsync(Exception? error = null, CancellationToken cancellationToken = default)
4949
{
5050
// Only run the full stdio cleanup once (handler detach, process kill, etc.).
51-
// But always call base.CleanupAsync — it cancels the shutdown CTS (which
52-
// unblocks the primary path if it's stuck in WaitForExitAsync), waits for
53-
// the read task to complete (so the primary path can call SetDisconnected
54-
// with full StdioClientCompletionDetails), and calls SetDisconnected itself
55-
// as a fallback. We wrap the error in TransportClosedException so the
56-
// fallback SetDisconnected still produces StdioClientCompletionDetails
57-
// rather than a bare ClientCompletionDetails.
51+
// If another call is already handling cleanup, cancel the shutdown token
52+
// to unblock it (e.g. if it's stuck in WaitForExitAsync) and let it
53+
// call SetDisconnected with full StdioClientCompletionDetails.
5854
if (Interlocked.Exchange(ref _cleanedUp, 1) != 0)
5955
{
60-
await base.CleanupAsync(new TransportClosedException(BuildCompletionDetails(error)), cancellationToken).ConfigureAwait(false);
56+
CancelShutdown();
6157
return;
6258
}
6359

src/ModelContextProtocol.Core/Client/StdioClientTransport.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public async Task<ITransport> ConnectAsync(CancellationToken cancellationToken =
137137
// few lines in a rolling log for use in exceptions.
138138
const int MaxStderrLength = 10; // keep the last 10 lines of stderr
139139
Queue<string> stderrRollingLog = new(MaxStderrLength);
140-
process.ErrorDataReceived += errorHandler = (sender, args) =>
140+
errorHandler = (sender, args) =>
141141
{
142142
string? data = args.Data;
143143
if (data is not null)
@@ -167,6 +167,7 @@ public async Task<ITransport> ConnectAsync(CancellationToken cancellationToken =
167167
LogReadStderr(logger, endpointName, data);
168168
}
169169
};
170+
process.ErrorDataReceived += errorHandler;
170171

171172
// We need both stdin and stdout to use a no-BOM UTF-8 encoding. On .NET Core,
172173
// we can use ProcessStartInfo.StandardOutputEncoding/StandardInputEncoding, but

src/ModelContextProtocol.Core/Client/StreamClientSessionTransport.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,21 @@ private async Task ProcessMessageAsync(string line, CancellationToken cancellati
164164
}
165165
}
166166

167+
/// <summary>
168+
/// Cancels the shutdown token to signal that the transport is shutting down,
169+
/// without performing any other cleanup.
170+
/// </summary>
171+
protected void CancelShutdown()
172+
{
173+
try
174+
{
175+
_shutdownCts?.Cancel();
176+
}
177+
catch (ObjectDisposedException)
178+
{
179+
}
180+
}
181+
167182
protected virtual async ValueTask CleanupAsync(Exception? error = null, CancellationToken cancellationToken = default)
168183
{
169184
LogTransportShuttingDown(Name);

0 commit comments

Comments
 (0)