Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageVersion Include="Basic.Reference.Assemblies.Net90" Version="1.8.3" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.4" />
<PackageVersion Include="CaseConverter" Version="2.0.1" />
<PackageVersion Include="ChilliCream.ModelContextProtocol.AspNetCore" Version="1.1.0" />
<PackageVersion Include="ChilliCream.ModelContextProtocol.AspNetCore" Version="1.2.0" />
<PackageVersion Include="ChilliCream.Nitro.App" Version="$(NitroVersion)" />
<PackageVersion Include="ChilliCream.Testing.Utilities" Version="0.2.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,40 +47,19 @@ 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(
new ProducesResponseTypeMetadata(
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<SseHandlerProxy>(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));
}
Comment thread
glen-84 marked this conversation as resolved.

return mcpGroup;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ public static void AddMcpServices(this IServiceCollection services, string schem
.AddKeyedSingleton(
schemaName,
static (sp, name) => new StreamableHttpHandlerProxy(
sp.GetRequiredKeyedService<McpRequestExecutorProxy>(name)))
.AddKeyedSingleton(
schemaName,
static (sp, name) => new SseHandlerProxy(
sp.GetRequiredKeyedService<McpRequestExecutorProxy>(name)));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@

namespace HotChocolate.Adapters.Mcp.Proxies;

internal sealed record McpExecutorSession(
StreamableHttpHandler StreamableHttpHandler,
SseHandler SseHandler);
internal sealed record McpExecutorSession(StreamableHttpHandler StreamableHttpHandler);
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,7 @@ protected override void OnConfigureRequestExecutor(
oldExecutor.Schema.Services.GetRequiredService<ConcurrentDictionary<string, McpServer>>());
}

var session =
new McpExecutorSession(
newExecutor.Schema.Services.GetRequiredService<StreamableHttpHandler>(),
newExecutor.Schema.Services.GetRequiredService<SseHandler>());
var session = new McpExecutorSession(newExecutor.Schema.Services.GetRequiredService<StreamableHttpHandler>());

newExecutor.Features.Set(session);
_session = session;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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<CallToolRequestParams>(mockServer.Object, request)
{
Params = new CallToolRequestParams
return new RequestContext<CallToolRequestParams>(
mockServer.Object,
request,
new CallToolRequestParams
{
Name = toolName
}
};
});
}
}
Loading