Fix stateless HTTP transport advertising listChanged capability (#1509)

This commit is contained in:
Jayaraman Venkatesan 2026-04-09 17:30:12 -04:00 • committed by GitHub
commit 07435dcb16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 0 deletions

View file

@ -98,6 +98,18 @@ internal sealed partial class McpServerImpl : McpServer
_notificationHandlers.RegisterRange(notificationHandlers);
}
// In stateless mode, the server cannot send unsolicited notifications,
// so listChanged should not be advertised.
if (transport is StreamableHttpServerTransport { Stateless: true })
{
if (ServerCapabilities.Tools is not null)
ServerCapabilities.Tools.ListChanged = null;
if (ServerCapabilities.Prompts is not null)
ServerCapabilities.Prompts.ListChanged = null;
if (ServerCapabilities.Resources is not null)
ServerCapabilities.Resources.ListChanged = null;
}
// Now that everything has been configured, subscribe to any necessary notifications.
if (transport is not StreamableHttpServerTransport streamableHttpTransport || streamableHttpTransport.Stateless is false)
{

View file

@ -292,6 +292,32 @@ public class StatelessServerTests(ITestOutputHelper outputHelper) : KestrelInMem
Assert.Equal("configured-beta", Assert.IsType<TextContentBlock>(content2).Text);
}
[Fact]
public async Task StatelessMode_DoesNotAdvertise_ListChangedCapabilities()
{
Builder.Services.AddMcpServer()
.WithHttpTransport(options =>
{
options.Stateless = true;
})
.WithTools([McpServerTool.Create(() => "result", new() { Name = "myTool" })])
.WithPrompts([McpServerPrompt.Create(() => new GetPromptResult(), new() { Name = "myPrompt" })])
.WithResources([McpServerResource.Create(() => new ReadResourceResult(), new() { UriTemplate = "resource://test" })]);
_app = Builder.Build();
_app.MapMcp();
await _app.StartAsync(TestContext.Current.CancellationToken);
HttpClient.DefaultRequestHeaders.Accept.Add(new("application/json"));
HttpClient.DefaultRequestHeaders.Accept.Add(new("text/event-stream"));
await using var client = await ConnectMcpClientAsync();
Assert.Null(client.ServerCapabilities.Tools?.ListChanged);
Assert.Null(client.ServerCapabilities.Prompts?.ListChanged);
Assert.Null(client.ServerCapabilities.Resources?.ListChanged);
}
[McpServerTool(Name = "testSamplingErrors")]
public static async Task<string> TestSamplingErrors(McpServer server)
{