Send DELETE request when closing a Streamable HTTP session on the client (#501)
This commit is contained in:
parent
befa31d5c9
commit
a4b4edaa2a
1 changed files with 93 additions and 11 deletions
|
|
@ -14,8 +14,10 @@ namespace ModelContextProtocol.AspNetCore.Tests;
|
|||
public class StreamableHttpClientConformanceTests(ITestOutputHelper outputHelper) : KestrelInMemoryTest(outputHelper), IAsyncDisposable
|
||||
{
|
||||
private WebApplication? _app;
|
||||
private readonly List<string> _deleteRequestSessionIds = [];
|
||||
|
||||
private async Task StartAsync()
|
||||
// Don't add the delete endpoint by default to ensure the client still works with basic sessionless servers.
|
||||
private async Task StartAsync(bool enableDelete = false)
|
||||
{
|
||||
Builder.Services.Configure<JsonOptions>(options =>
|
||||
{
|
||||
|
|
@ -28,7 +30,7 @@ public class StreamableHttpClientConformanceTests(ITestOutputHelper outputHelper
|
|||
Services = _app.Services,
|
||||
});
|
||||
|
||||
_app.MapPost("/mcp", (JsonRpcMessage message) =>
|
||||
_app.MapPost("/mcp", (JsonRpcMessage message, HttpContext context) =>
|
||||
{
|
||||
if (message is not JsonRpcRequest request)
|
||||
{
|
||||
|
|
@ -36,6 +38,12 @@ public class StreamableHttpClientConformanceTests(ITestOutputHelper outputHelper
|
|||
return Results.Accepted();
|
||||
}
|
||||
|
||||
if (enableDelete)
|
||||
{
|
||||
// Add a session ID to the response to enable session tracking
|
||||
context.Response.Headers.Append("mcp-session-id", "test-session-123");
|
||||
}
|
||||
|
||||
if (request.Method == "initialize")
|
||||
{
|
||||
return Results.Json(new JsonRpcResponse
|
||||
|
|
@ -87,6 +95,15 @@ public class StreamableHttpClientConformanceTests(ITestOutputHelper outputHelper
|
|||
throw new Exception("Unexpected message!");
|
||||
});
|
||||
|
||||
if (enableDelete)
|
||||
{
|
||||
_app.MapDelete("/mcp", context =>
|
||||
{
|
||||
_deleteRequestSessionIds.Add(context.Request.Headers["mcp-session-id"].ToString());
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
await _app.StartAsync(TestContext.Current.CancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +153,27 @@ public class StreamableHttpClientConformanceTests(ITestOutputHelper outputHelper
|
|||
await Task.WhenAll(echoTasks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendsDeleteRequestOnDispose()
|
||||
{
|
||||
await StartAsync(enableDelete: true);
|
||||
|
||||
await using var transport = new SseClientTransport(new()
|
||||
{
|
||||
Endpoint = new("http://localhost/mcp"),
|
||||
TransportMode = HttpTransportMode.StreamableHttp,
|
||||
}, HttpClient, LoggerFactory);
|
||||
|
||||
await using var client = await McpClientFactory.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Dispose should trigger DELETE request
|
||||
await client.DisposeAsync();
|
||||
|
||||
// Verify DELETE request was sent with correct session ID
|
||||
var sessionId = Assert.Single(_deleteRequestSessionIds);
|
||||
Assert.Equal("test-session-123", sessionId);
|
||||
}
|
||||
|
||||
private static async Task CallEchoAndValidateAsync(McpClientTool echoTool)
|
||||
{
|
||||
var response = await echoTool.CallAsync(new Dictionary<string, object?>() { ["message"] = "Hello world!" }, cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
|
|
|||
Loading…
Reference in a new issue