diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 91b29b2ae28..ec8d2baf847 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -12,7 +12,7 @@ - + diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/EndpointRouteBuilderExtensions.cs b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/EndpointRouteBuilderExtensions.cs index dc30c8fe49a..5a5b130714b 100644 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/EndpointRouteBuilderExtensions.cs +++ b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/EndpointRouteBuilderExtensions.cs @@ -47,9 +47,9 @@ public static IEndpointConventionBuilder MapGraphQLMcp( if (!streamableHttpHandler.HttpServerTransportOptions.Stateless) { - // The GET and DELETE endpoints are not mapped in Stateless mode since there's no way to - // send unsolicited messages for the GET to handle, and there is no server-side state - // for the DELETE to clean up. + // The GET endpoint is not mapped in Stateless mode since there's no way to send + // unsolicited messages. Resuming streams via GET is currently not supported in + // Stateless mode. streamableHttpGroup .MapGet("", streamableHttpHandler.HandleGetRequestAsync) .WithMetadata( @@ -57,30 +57,9 @@ public static IEndpointConventionBuilder MapGraphQLMcp( StatusCodes.Status200OK, contentTypes: ["text/event-stream"])); + // The DELETE endpoint is not mapped in Stateless mode since there is no server-side + // state for the DELETE to clean up. streamableHttpGroup.MapDelete("", streamableHttpHandler.HandleDeleteRequestAsync); - - // Map legacy HTTP with SSE endpoints only if not in Stateless mode, because we cannot - // guarantee the /message requests will be handled by the same process as the /sse - // request. - var sseHandler = - endpoints.ServiceProvider.GetRequiredKeyedService(schemaName); - - var sseGroup = - mcpGroup - .MapGroup("") - .WithDisplayName(b => $"GraphQL MCP HTTP with SSE | {b.DisplayName}"); - - sseGroup - .MapGet("/sse", sseHandler.HandleSseRequestAsync) - .WithMetadata( - new ProducesResponseTypeMetadata( - StatusCodes.Status200OK, - contentTypes: ["text/event-stream"])); - - sseGroup - .MapPost("/message", sseHandler.HandleMessageRequestAsync) - .WithMetadata(new AcceptsMetadata(["application/json"])) - .WithMetadata(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted)); } return mcpGroup; diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/ServiceCollectionExtensions.cs b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/ServiceCollectionExtensions.cs index 79125587170..ca0f9aec807 100644 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/ServiceCollectionExtensions.cs +++ b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/ServiceCollectionExtensions.cs @@ -34,10 +34,6 @@ public static void AddMcpServices(this IServiceCollection services, string schem .AddKeyedSingleton( schemaName, static (sp, name) => new StreamableHttpHandlerProxy( - sp.GetRequiredKeyedService(name))) - .AddKeyedSingleton( - schemaName, - static (sp, name) => new SseHandlerProxy( sp.GetRequiredKeyedService(name))); } diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpExecutorSession.cs b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpExecutorSession.cs index 2ce0b6c2382..42a36b2712b 100644 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpExecutorSession.cs +++ b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpExecutorSession.cs @@ -2,6 +2,4 @@ namespace HotChocolate.Adapters.Mcp.Proxies; -internal sealed record McpExecutorSession( - StreamableHttpHandler StreamableHttpHandler, - SseHandler SseHandler); +internal sealed record McpExecutorSession(StreamableHttpHandler StreamableHttpHandler); diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpRequestExecutorProxy.cs b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpRequestExecutorProxy.cs index 23b57cc590b..d63ebb910a7 100644 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpRequestExecutorProxy.cs +++ b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/McpRequestExecutorProxy.cs @@ -49,10 +49,7 @@ protected override void OnConfigureRequestExecutor( oldExecutor.Schema.Services.GetRequiredService>()); } - var session = - new McpExecutorSession( - newExecutor.Schema.Services.GetRequiredService(), - newExecutor.Schema.Services.GetRequiredService()); + var session = new McpExecutorSession(newExecutor.Schema.Services.GetRequiredService()); newExecutor.Features.Set(session); _session = session; diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/SseHandlerProxy.cs b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/SseHandlerProxy.cs deleted file mode 100644 index 5689e44f3c1..00000000000 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Proxies/SseHandlerProxy.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace HotChocolate.Adapters.Mcp.Proxies; - -internal sealed class SseHandlerProxy -{ - private readonly McpRequestExecutorProxy _mcpRequestExecutor; - - public SseHandlerProxy(McpRequestExecutorProxy mcpRequestExecutor) - { - ArgumentNullException.ThrowIfNull(mcpRequestExecutor); - _mcpRequestExecutor = mcpRequestExecutor; - } - - public async Task HandleSseRequestAsync(HttpContext context) - { - var session = await _mcpRequestExecutor.GetOrCreateSessionAsync(context.RequestAborted); - await session.SseHandler.HandleSseRequestAsync(context); - } - - public async Task HandleMessageRequestAsync(HttpContext context) - { - var session = await _mcpRequestExecutor.GetOrCreateSessionAsync(context.RequestAborted); - await session.SseHandler.HandleMessageRequestAsync(context); - } -} diff --git a/src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/Handlers/CallToolHandlerTests.cs b/src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/Handlers/CallToolHandlerTests.cs index ae2f849fefd..4cb6d066c25 100644 --- a/src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/Handlers/CallToolHandlerTests.cs +++ b/src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/Handlers/CallToolHandlerTests.cs @@ -53,12 +53,12 @@ await storage.AddOrUpdateToolAsync( mockServer.SetupGet(s => s.Services).Returns(executor.Schema.Services); var request = new JsonRpcRequest { Method = RequestMethods.ToolsCall }; - return new RequestContext(mockServer.Object, request) - { - Params = new CallToolRequestParams + return new RequestContext( + mockServer.Object, + request, + new CallToolRequestParams { Name = toolName - } - }; + }); } }