csharp-sdk/tests/ModelContextProtocol.AspNetCore.Tests/SseServerIntegrationTests.cs
Copilot 2e17550303
Add X-Accel-Buffering header to SSE responses (#1294)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
2026-02-17 16:03:10 -05:00

70 lines
3.4 KiB
C#

using ModelContextProtocol.Client;
using System.Net;
using System.Text;
namespace ModelContextProtocol.AspNetCore.Tests;
public class SseServerIntegrationTests(SseServerIntegrationTestFixture fixture, ITestOutputHelper testOutputHelper)
: HttpServerIntegrationTests(fixture, testOutputHelper)
{
protected override HttpClientTransportOptions ClientTransportOptions => new()
{
Endpoint = new("http://localhost:5000/sse"),
Name = "In-memory SSE Client",
};
[Fact]
public async Task EventSourceResponse_Includes_ExpectedHeaders()
{
using var sseResponse = await _fixture.HttpClient.GetAsync("/sse", HttpCompletionOption.ResponseHeadersRead, TestContext.Current.CancellationToken);
sseResponse.EnsureSuccessStatusCode();
Assert.Equal("text/event-stream", sseResponse.Content.Headers.ContentType?.MediaType);
Assert.Equal("identity", sseResponse.Content.Headers.ContentEncoding.ToString());
Assert.NotNull(sseResponse.Headers.CacheControl);
Assert.True(sseResponse.Headers.CacheControl.NoStore);
Assert.True(sseResponse.Headers.CacheControl.NoCache);
Assert.Equal("no", Assert.Single(sseResponse.Headers.GetValues("X-Accel-Buffering")));
}
[Fact]
public async Task EventSourceStream_Includes_MessageEventType()
{
// Simulate our own MCP client handshake using a plain HttpClient so we can look for "event: message"
// in the raw SSE response stream which is not exposed by the real MCP client.
await using var sseResponse = await _fixture.HttpClient.GetStreamAsync("/sse", TestContext.Current.CancellationToken);
using var streamReader = new StreamReader(sseResponse);
var endpointEvent = await streamReader.ReadLineAsync(TestContext.Current.CancellationToken);
Assert.Equal("event: endpoint", endpointEvent);
var endpointData = await streamReader.ReadLineAsync(TestContext.Current.CancellationToken);
Assert.NotNull(endpointData);
Assert.StartsWith("data: ", endpointData);
var messageEndpoint = endpointData["data: ".Length..];
const string initializeRequest = """
{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"IntegrationTestClient","version":"1.0.0"}}}
""";
using (var initializeRequestBody = new StringContent(initializeRequest, Encoding.UTF8, "application/json"))
{
using var response = await _fixture.HttpClient.PostAsync(messageEndpoint, initializeRequestBody, TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
}
const string initializedNotification = """
{"jsonrpc":"2.0","method":"notifications/initialized"}
""";
using (var initializedNotificationBody = new StringContent(initializedNotification, Encoding.UTF8, "application/json"))
{
using var response = await _fixture.HttpClient.PostAsync(messageEndpoint, initializedNotificationBody, TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
}
Assert.Equal("", await streamReader.ReadLineAsync(TestContext.Current.CancellationToken));
var messageEvent = await streamReader.ReadLineAsync(TestContext.Current.CancellationToken);
Assert.Equal("event: message", messageEvent);
}
}