Fix stateless HTTP transport advertising listChanged capability (#1509)
This commit is contained in:
parent
6a02c5a1b0
commit
07435dcb16
2 changed files with 38 additions and 0 deletions
|
|
@ -98,6 +98,18 @@ internal sealed partial class McpServerImpl : McpServer
|
||||||
_notificationHandlers.RegisterRange(notificationHandlers);
|
_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.
|
// Now that everything has been configured, subscribe to any necessary notifications.
|
||||||
if (transport is not StreamableHttpServerTransport streamableHttpTransport || streamableHttpTransport.Stateless is false)
|
if (transport is not StreamableHttpServerTransport streamableHttpTransport || streamableHttpTransport.Stateless is false)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,32 @@ public class StatelessServerTests(ITestOutputHelper outputHelper) : KestrelInMem
|
||||||
Assert.Equal("configured-beta", Assert.IsType<TextContentBlock>(content2).Text);
|
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")]
|
[McpServerTool(Name = "testSamplingErrors")]
|
||||||
public static async Task<string> TestSamplingErrors(McpServer server)
|
public static async Task<string> TestSamplingErrors(McpServer server)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue