From c96970f97d20742bf0fa6c398fb30b3f791f787e Mon Sep 17 00:00:00 2001 From: dogdie233 Date: Thu, 17 Apr 2025 19:13:02 +0800 Subject: [PATCH 1/4] update test to verify routing pattern is included in `/message` endpoint #280 currently expected to fail until fix is implemented --- .../MapMcpTests.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs index f7cb2c8a6..703c6deab 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs @@ -38,12 +38,22 @@ public async Task Allows_Customizing_Route() Builder.Services.AddMcpServer().WithHttpTransport(); await using var app = Builder.Build(); - app.MapMcp("/mcp"); + var pattern = "/mcp"; + + app.MapMcp(pattern); await app.StartAsync(TestContext.Current.CancellationToken); using var response = await HttpClient.GetAsync("http://localhost/mcp/sse", HttpCompletionOption.ResponseHeadersRead, TestContext.Current.CancellationToken); response.EnsureSuccessStatusCode(); + using var sseStream = await response.Content.ReadAsStreamAsync(TestContext.Current.CancellationToken); + using var sseStreamReader = new StreamReader(sseStream, System.Text.Encoding.UTF8); + var eventLine = await sseStreamReader.ReadLineAsync(TestContext.Current.CancellationToken); + var dataLine = await sseStreamReader.ReadLineAsync(TestContext.Current.CancellationToken); + Assert.NotNull(eventLine); + Assert.Equal("event: endpoint", eventLine); + Assert.NotNull(dataLine); + Assert.Equal($"data: {pattern}/message", dataLine[..dataLine.IndexOf('?')]); } [Theory] From 74d3ca6fcbb33a10531f703ff62def69ac652a2f Mon Sep 17 00:00:00 2001 From: dogdie233 Date: Thu, 17 Apr 2025 19:33:38 +0800 Subject: [PATCH 2/4] fix routing pattern not included in /message endpoint when using SSE Server #280 --- src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs b/src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs index b88cc07c6..19fb6f1fb 100644 --- a/src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs +++ b/src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs @@ -58,7 +58,9 @@ public async Task HandleSseRequestAsync(HttpContext context) context.Features.GetRequiredFeature().DisableBuffering(); var sessionId = MakeNewSessionId(); - await using var transport = new SseResponseStreamTransport(response.Body, $"message?sessionId={sessionId}"); + var requestPath = context.Request.Path; + var endpointPattern = requestPath.HasValue ? requestPath.Value[..(requestPath.Value.LastIndexOf('/') + 1)] : string.Empty; + await using var transport = new SseResponseStreamTransport(response.Body, $"{endpointPattern}message?sessionId={sessionId}"); var httpMcpSession = new HttpMcpSession(transport, context.User); if (!_sessions.TryAdd(sessionId, httpMcpSession)) { From a94eca036a97e063bf2699bcb9031fd6810db111 Mon Sep 17 00:00:00 2001 From: dogdie233 Date: Thu, 17 Apr 2025 19:43:05 +0800 Subject: [PATCH 3/4] Update Allows_Customizing_Route test to check subpath --- .../MapMcpTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs index 703c6deab..c0cee947b 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs @@ -32,19 +32,19 @@ public async Task MapMcp_ThrowsInvalidOperationException_IfWithHttpTransportIsNo Assert.StartsWith("You must call WithHttpTransport()", exception.Message); } - [Fact] - public async Task Allows_Customizing_Route() + [Theory] + [InlineData("/mcp")] + [InlineData("/mcp/secondary")] + public async Task Allows_Customizing_Route(string pattern) { Builder.Services.AddMcpServer().WithHttpTransport(); await using var app = Builder.Build(); - var pattern = "/mcp"; - app.MapMcp(pattern); await app.StartAsync(TestContext.Current.CancellationToken); - using var response = await HttpClient.GetAsync("http://localhost/mcp/sse", HttpCompletionOption.ResponseHeadersRead, TestContext.Current.CancellationToken); + using var response = await HttpClient.GetAsync($"http://localhost{pattern}/sse", HttpCompletionOption.ResponseHeadersRead, TestContext.Current.CancellationToken); response.EnsureSuccessStatusCode(); using var sseStream = await response.Content.ReadAsStreamAsync(TestContext.Current.CancellationToken); using var sseStreamReader = new StreamReader(sseStream, System.Text.Encoding.UTF8); From e037c4f63a472e5831dc01d8c70a84cb4957945c Mon Sep 17 00:00:00 2001 From: dogdie233 Date: Sun, 20 Apr 2025 21:34:24 +0800 Subject: [PATCH 4/4] Reapply patch with PathBase consideration, add test cases --- src/ModelContextProtocol.AspNetCore/SseHandler.cs | 4 +++- tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ModelContextProtocol.AspNetCore/SseHandler.cs b/src/ModelContextProtocol.AspNetCore/SseHandler.cs index 638592198..36efadef4 100644 --- a/src/ModelContextProtocol.AspNetCore/SseHandler.cs +++ b/src/ModelContextProtocol.AspNetCore/SseHandler.cs @@ -31,7 +31,9 @@ public async Task HandleSseRequestAsync(HttpContext context) StreamableHttpHandler.InitializeSseResponse(context); - await using var transport = new SseResponseStreamTransport(context.Response.Body, $"message?sessionId={sessionId}"); + var requestPath = (context.Request.PathBase + context.Request.Path).ToString(); + var endpointPattern = requestPath[..(requestPath.LastIndexOf('/') + 1)]; + await using var transport = new SseResponseStreamTransport(context.Response.Body, $"{endpointPattern}message?sessionId={sessionId}"); await using var httpMcpSession = new HttpMcpSession(sessionId, transport, context.User, httpMcpServerOptions.Value.TimeProvider); if (!_sessions.TryAdd(sessionId, httpMcpSession)) { diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs index b5845673c..f11a0a51a 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs @@ -59,6 +59,7 @@ public async Task Allows_Customizing_Route(string pattern) [Theory] [InlineData("/a", "/a/sse")] [InlineData("/a/", "/a/sse")] + [InlineData("/a/b", "/a/b/sse")] public async Task CanConnect_WithMcpClient_AfterCustomizingRoute(string routePattern, string requestPath) { Builder.Services.AddMcpServer(options =>