Skip to content

Commit 3a2e9a2

Browse files
authored
Fix race in KestrelInMemoryConnection (#233)
* Also remove some duplication from WithStdioServerTransport and WithStreamServerTransport
1 parent 82510d5 commit 3a2e9a2

File tree

4 files changed

+16
-22
lines changed

4 files changed

+16
-22
lines changed

samples/AspNetCoreSseServer/Properties/launchSettings.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"http": {
55
"commandName": "Project",
66
"dotnetRunMessages": true,
7-
"launchBrowser": true,
87
"applicationUrl": "http://localhost:3001",
98
"environmentVariables": {
109
"ASPNETCORE_ENVIRONMENT": "Development"
@@ -13,7 +12,6 @@
1312
"https": {
1413
"commandName": "Project",
1514
"dotnetRunMessages": true,
16-
"launchBrowser": true,
1715
"applicationUrl": "https://localhost:7133;http://localhost:3001",
1816
"environmentVariables": {
1917
"ASPNETCORE_ENVIRONMENT": "Development"

src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.cs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Extensions.Logging;
1+
using Microsoft.Extensions.DependencyInjection.Extensions;
2+
using Microsoft.Extensions.Logging;
23
using Microsoft.Extensions.Options;
34
using ModelContextProtocol.Hosting;
45
using ModelContextProtocol.Protocol.Transport;
@@ -348,17 +349,8 @@ public static IMcpServerBuilder WithStdioServerTransport(this IMcpServerBuilder
348349
{
349350
Throw.IfNull(builder);
350351

352+
AddSingleSessionServerDependencies(builder.Services);
351353
builder.Services.AddSingleton<ITransport, StdioServerTransport>();
352-
builder.Services.AddHostedService<SingleSessionMcpServerHostedService>();
353-
354-
builder.Services.AddSingleton(services =>
355-
{
356-
ITransport serverTransport = services.GetRequiredService<ITransport>();
357-
IOptions<McpServerOptions> options = services.GetRequiredService<IOptions<McpServerOptions>>();
358-
ILoggerFactory? loggerFactory = services.GetService<ILoggerFactory>();
359-
360-
return McpServerFactory.Create(serverTransport, options.Value, loggerFactory, services);
361-
});
362354

363355
return builder;
364356
}
@@ -378,19 +370,22 @@ public static IMcpServerBuilder WithStreamServerTransport(
378370
Throw.IfNull(inputStream);
379371
Throw.IfNull(outputStream);
380372

373+
AddSingleSessionServerDependencies(builder.Services);
381374
builder.Services.AddSingleton<ITransport>(new StreamServerTransport(inputStream, outputStream));
382-
builder.Services.AddHostedService<SingleSessionMcpServerHostedService>();
383375

384-
builder.Services.AddSingleton(services =>
376+
return builder;
377+
}
378+
379+
private static void AddSingleSessionServerDependencies(IServiceCollection services)
380+
{
381+
services.AddHostedService<SingleSessionMcpServerHostedService>();
382+
services.TryAddSingleton(services =>
385383
{
386384
ITransport serverTransport = services.GetRequiredService<ITransport>();
387385
IOptions<McpServerOptions> options = services.GetRequiredService<IOptions<McpServerOptions>>();
388386
ILoggerFactory? loggerFactory = services.GetService<ILoggerFactory>();
389-
390387
return McpServerFactory.Create(serverTransport, options.Value, loggerFactory, services);
391388
});
392-
393-
return builder;
394389
}
395390
#endregion
396391
}

tests/ModelContextProtocol.Tests/Transport/SseClientTransportTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public async Task SendMessageAsync_Handles_Accepted_Json_RPC_Response()
148148

149149
var eventSourcePipe = new Pipe();
150150
var eventSourceData = "event: endpoint\r\ndata: /sseendpoint\r\n\r\n"u8;
151-
Assert.True(eventSourceData.TryCopyTo(eventSourcePipe.Writer.GetSpan()));
151+
eventSourceData.CopyTo(eventSourcePipe.Writer.GetSpan(eventSourceData.Length));
152152
eventSourcePipe.Writer.Advance(eventSourceData.Length);
153153
await eventSourcePipe.Writer.FlushAsync(TestContext.Current.CancellationToken);
154154

tests/ModelContextProtocol.Tests/Utils/KestrelInMemoryConnection.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ public override ValueTask DisposeAsync()
4343
// completes the other half of these pipes.
4444
_serverToClientPipe.Writer.Complete();
4545
_serverToClientPipe.Reader.Complete();
46-
// Disposing the CTS without waiting for the client would be problematic
47-
// except we always dispose the HttpClient before Kestrel in our tests.
48-
_connectionClosedCts.Dispose();
46+
47+
// Don't bother disposing the _connectionClosedCts, since this is just for testing,
48+
// and it's annoying to synchronize with DuplexStream.
49+
4950
return base.DisposeAsync();
5051
}
5152

0 commit comments

Comments
 (0)