diff --git a/src/ModelContextProtocol/Client/SseClientSessionTransport.cs b/src/ModelContextProtocol/Client/SseClientSessionTransport.cs index 78997b5e8..b29306e13 100644 --- a/src/ModelContextProtocol/Client/SseClientSessionTransport.cs +++ b/src/ModelContextProtocol/Client/SseClientSessionTransport.cs @@ -92,26 +92,18 @@ public override async Task SendMessageAsync( StreamableHttpClientSessionTransport.CopyAdditionalHeaders(httpRequestMessage.Headers, _options.AdditionalHeaders); var response = await _httpClient.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false); - response.EnsureSuccessStatusCode(); - - var responseContent = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); - - if (string.IsNullOrEmpty(responseContent) || responseContent.Equals("accepted", StringComparison.OrdinalIgnoreCase)) - { - LogAcceptedPost(Name, messageId); - } - else + if (!response.IsSuccessStatusCode) { if (_logger.IsEnabled(LogLevel.Trace)) { - LogRejectedPostSensitive(Name, messageId, responseContent); + LogRejectedPostSensitive(Name, messageId, await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); } else { LogRejectedPost(Name, messageId); } - throw new InvalidOperationException("Failed to send message"); + response.EnsureSuccessStatusCode(); } } diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/SseIntegrationTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/SseIntegrationTests.cs index 24acd0b92..fc186c400 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/SseIntegrationTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/SseIntegrationTests.cs @@ -58,6 +58,22 @@ public async Task ConnectAndReceiveMessage_InMemoryServer_WithFullEndpointEventU Assert.True(true); } + [Fact] + public async Task ConnectAndReceiveMessage_ServerReturningJsonInPostRequest() + { + await using var app = Builder.Build(); + MapAbsoluteEndpointUriMcp(app, respondInJson: true); + + await app.StartAsync(TestContext.Current.CancellationToken); + + await using var mcpClient = await ConnectMcpClientAsync(); + + // Send a test message through POST endpoint + await mcpClient.SendNotificationAsync("test/message", new Envelope { Message = "Hello, SSE!" }, serializerOptions: JsonContext.Default.Options, cancellationToken: TestContext.Current.CancellationToken); + + Assert.True(true); + } + [Fact] public async Task ConnectAndReceiveNotification_InMemoryServer() { @@ -220,7 +236,7 @@ public async Task EmptyAdditionalHeadersKey_Throws_InvalidOperationException() Assert.Equal("Failed to add header '' with value '' from AdditionalHeaders.", ex.Message); } - private static void MapAbsoluteEndpointUriMcp(IEndpointRouteBuilder endpoints) + private static void MapAbsoluteEndpointUriMcp(IEndpointRouteBuilder endpoints, bool respondInJson = false) { var loggerFactory = endpoints.ServiceProvider.GetRequiredService(); var optionsSnapshot = endpoints.ServiceProvider.GetRequiredService>(); @@ -267,7 +283,7 @@ private static void MapAbsoluteEndpointUriMcp(IEndpointRouteBuilder endpoints) await Results.BadRequest("Session not started.").ExecuteAsync(context); return; } - var message = (JsonRpcMessage?)await context.Request.ReadFromJsonAsync(McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(JsonRpcMessage)), context.RequestAborted); + var message = await context.Request.ReadFromJsonAsync(McpJsonUtilities.DefaultOptions, context.RequestAborted); if (message is null) { await Results.BadRequest("No message in request body.").ExecuteAsync(context); @@ -276,7 +292,15 @@ private static void MapAbsoluteEndpointUriMcp(IEndpointRouteBuilder endpoints) await session.OnMessageReceivedAsync(message, context.RequestAborted); context.Response.StatusCode = StatusCodes.Status202Accepted; - await context.Response.WriteAsync("Accepted"); + + if (respondInJson) + { + await context.Response.WriteAsJsonAsync(message, McpJsonUtilities.DefaultOptions, cancellationToken: context.RequestAborted); + } + else + { + await context.Response.WriteAsync("Accepted"); + } }); }