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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using HotChocolate.Adapters.Mcp.Proxies;
using HotChocolate.Execution;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Metadata;
Expand All @@ -16,6 +17,7 @@ public static IEndpointConventionBuilder MapGraphQLMcp(
[StringSyntax("Route")] string pattern = "/graphql/mcp",
string? schemaName = null)
{
TryResolveSchemaName(endpoints.ServiceProvider, ref schemaName);
schemaName ??= ISchemaDefinition.DefaultName;

var streamableHttpHandler =
Expand Down Expand Up @@ -64,4 +66,14 @@ public static IEndpointConventionBuilder MapGraphQLMcp(

return mcpGroup;
}

private static void TryResolveSchemaName(IServiceProvider services, ref string? schemaName)
{
if (schemaName is null
&& services.GetService<IRequestExecutorProvider>() is { } provider
&& provider.SchemaNames.Length == 1)
{
schemaName = provider.SchemaNames[0];
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using HotChocolate.Execution;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -9,6 +10,7 @@ public static IEndpointRouteBuilder MapOpenApiEndpoints(
this IEndpointRouteBuilder endpoints,
string? schemaName = null)
{
TryResolveSchemaName(endpoints.ServiceProvider, ref schemaName);
schemaName ??= ISchemaDefinition.DefaultName;

var dataSource = endpoints.ServiceProvider.GetRequiredKeyedService<DynamicEndpointDataSource>(schemaName);
Comment thread
tobias-tengler marked this conversation as resolved.
Expand All @@ -20,4 +22,14 @@ public static IEndpointRouteBuilder MapOpenApiEndpoints(

return endpoints;
}

private static void TryResolveSchemaName(IServiceProvider services, ref string? schemaName)
{
if (schemaName is null
&& services.GetService<IRequestExecutorProvider>() is { } provider
&& provider.SchemaNames.Length == 1)
{
schemaName = provider.SchemaNames[0];
}
}
Comment thread
tobias-tengler marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using HotChocolate.Execution;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -7,14 +8,26 @@ public static class OpenApiOptionsExtensions
{
public static OpenApiOptions AddGraphQLTransformer(this OpenApiOptions options, string? schemaName = null)
{
schemaName ??= ISchemaDefinition.DefaultName;

return options.AddDocumentTransformer((document, context, ct) =>
{
var resolvedSchemaName = schemaName;
TryResolveSchemaName(context.ApplicationServices, ref resolvedSchemaName);
resolvedSchemaName ??= ISchemaDefinition.DefaultName;

Comment thread
tobias-tengler marked this conversation as resolved.
var transformer = context.ApplicationServices
.GetRequiredKeyedService<DynamicOpenApiDocumentTransformer>(schemaName);
.GetRequiredKeyedService<DynamicOpenApiDocumentTransformer>(resolvedSchemaName);

return transformer.TransformAsync(document, context, ct);
});
}

private static void TryResolveSchemaName(IServiceProvider services, ref string? schemaName)
{
if (schemaName is null
&& services.GetService<IRequestExecutorProvider>() is { } provider
&& provider.SchemaNames.Length == 1)
{
schemaName = provider.SchemaNames[0];
}
}
Comment thread
tobias-tengler marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,42 @@

public sealed class CoreIntegrationTests : IntegrationTestBase
{
[Fact]
public async Task MapGraphQLMcp_Should_ResolveSchemaName_When_SingleNamedSchemaRegistered()
{
// arrange
var storage = new TestMcpStorage();
await storage.AddOrUpdateToolAsync(
new OperationToolDefinition(
Utf8GraphQLParser.Parse("query GetBooks { books { title } }")));
var builder = new WebHostBuilder()

Check warning on line 31 in src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/CoreIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.Mcp.Tests

'WebHostBuilder' is obsolete: 'WebHostBuilder is deprecated in favor of HostBuilder and WebApplicationBuilder. For more information, visit https://aka.ms/aspnet/deprecate/004.' (https://aka.ms/aspnet/deprecate/004)
.ConfigureServices(
services => services
.AddRouting()
.AddGraphQL("NamedSchema")
.AddAuthorization()
.AddQueryType<TestSchema.Query>()
.AddMutationType<TestSchema.Mutation>()
.AddInterfaceType<TestSchema.IPet>()
.AddUnionType<TestSchema.IPet>()
.AddObjectType<TestSchema.Cat>()
.AddObjectType<TestSchema.Dog>()
.AddMcp()
.AddMcpStorage(storage))
.Configure(
app => app
.UseRouting()
.UseEndpoints(endpoints => endpoints.MapGraphQLMcp()));
var server = new TestServer(builder);

Check warning on line 49 in src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/CoreIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.Mcp.Tests

'TestServer.TestServer(IWebHostBuilder)' is obsolete: 'IWebHost, which this method uses, is obsolete. Use one of the ctors that takes an IServiceProvider instead. For more information, visit https://aka.ms/aspnet/deprecate/008.' (https://aka.ms/aspnet/deprecate/008)
var mcpClient = await CreateMcpClientAsync(server.CreateClient());

// act
var tools = await mcpClient.ListToolsAsync();

// assert
Assert.Equal("get_books", Assert.Single(tools).Name);
}

[Fact]
public async Task ListTools_AfterSchemaUpdate_ReturnsUpdatedTools()
{
Expand All @@ -30,7 +66,7 @@
Utf8GraphQLParser.Parse(
await File.ReadAllTextAsync("__resources__/GetSingleField.graphql"))));
var typeModule = new TestTypeModule();
var builder = new WebHostBuilder()

Check warning on line 69 in src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/CoreIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.Mcp.Tests

'WebHostBuilder' is obsolete: 'WebHostBuilder is deprecated in favor of HostBuilder and WebApplicationBuilder. For more information, visit https://aka.ms/aspnet/deprecate/004.' (https://aka.ms/aspnet/deprecate/004)
.ConfigureServices(
services => services
.AddRouting()
Expand All @@ -42,7 +78,7 @@
app => app
.UseRouting()
.UseEndpoints(endpoints => endpoints.MapGraphQLMcp()));
var server = new TestServer(builder);

Check warning on line 81 in src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/CoreIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.Mcp.Tests

'TestServer.TestServer(IWebHostBuilder)' is obsolete: 'IWebHost, which this method uses, is obsolete. Use one of the ctors that takes an IServiceProvider instead. For more information, visit https://aka.ms/aspnet/deprecate/008.' (https://aka.ms/aspnet/deprecate/008)
var mcpClient1 = await CreateMcpClientAsync(server.CreateClient());
var mcpClient2 = await CreateMcpClientAsync(server.CreateClient());
var listChangedResetEvent1 = new ManualResetEventSlim(false);
Expand Down Expand Up @@ -101,7 +137,7 @@
Action<McpServerOptions>? configureMcpServerOptions = null,
Action<IMcpServerBuilder>? configureMcpServer = null)
{
var builder = new WebHostBuilder()

Check warning on line 140 in src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/CoreIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.Mcp.Tests

'WebHostBuilder' is obsolete: 'WebHostBuilder is deprecated in favor of HostBuilder and WebApplicationBuilder. For more information, visit https://aka.ms/aspnet/deprecate/004.' (https://aka.ms/aspnet/deprecate/004)
.ConfigureServices(
services =>
{
Expand Down Expand Up @@ -147,7 +183,7 @@
.UseAuthentication()
.UseEndpoints(endpoints => endpoints.MapGraphQLMcp()));

return Task.FromResult(new TestServer(builder));

Check warning on line 186 in src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/CoreIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.Mcp.Tests

'TestServer.TestServer(IWebHostBuilder)' is obsolete: 'IWebHost, which this method uses, is obsolete. Use one of the ctors that takes an IServiceProvider instead. For more information, visit https://aka.ms/aspnet/deprecate/008.' (https://aka.ms/aspnet/deprecate/008)
}

private sealed class TestTypeModule : TypeModule
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;

namespace HotChocolate.Adapters.OpenApi;
Expand All @@ -20,6 +24,41 @@
}
}

[Fact]
public async Task MapOpenApiEndpoints_Should_ResolveSchemaName_When_SingleNamedSchemaRegistered()
{
// arrange
var storage = new TestOpenApiDefinitionStorage(
"""
query GetUsers @http(method: GET, route: "/users") {
usersWithoutAuth {
id
}
}
""");
var builder = new WebHostBuilder()

Check warning on line 39 in src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/Endpoints/HttpEndpointIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.OpenApi.Tests

'WebHostBuilder' is obsolete: 'WebHostBuilder is deprecated in favor of HostBuilder and WebApplicationBuilder. For more information, visit https://aka.ms/aspnet/deprecate/004.' (https://aka.ms/aspnet/deprecate/004)

Check warning on line 39 in src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/Endpoints/HttpEndpointIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.OpenApi.Tests

'WebHostBuilder' is obsolete: 'WebHostBuilder is deprecated in favor of HostBuilder and WebApplicationBuilder. For more information, visit https://aka.ms/aspnet/deprecate/004.' (https://aka.ms/aspnet/deprecate/004)
.ConfigureServices(services =>
{
services.AddRouting();
services.AddGraphQLServer("NamedSchema")
.AddOpenApiDefinitionStorage(storage)
.AddBasicServer();
})
.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapOpenApiEndpoints());
});
var server = new TestServer(builder);

Check warning on line 52 in src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/Endpoints/HttpEndpointIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.OpenApi.Tests

'TestServer.TestServer(IWebHostBuilder)' is obsolete: 'IWebHost, which this method uses, is obsolete. Use one of the ctors that takes an IServiceProvider instead. For more information, visit https://aka.ms/aspnet/deprecate/008.' (https://aka.ms/aspnet/deprecate/008)

Check warning on line 52 in src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/Endpoints/HttpEndpointIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.OpenApi.Tests

'TestServer.TestServer(IWebHostBuilder)' is obsolete: 'IWebHost, which this method uses, is obsolete. Use one of the ctors that takes an IServiceProvider instead. For more information, visit https://aka.ms/aspnet/deprecate/008.' (https://aka.ms/aspnet/deprecate/008)
var client = server.CreateClient();

// act
var response = await client.GetAsync("/users");

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}

[Fact]
public async Task Http_Post_Body_Field_Has_Wrong_Type()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;

namespace HotChocolate.Adapters.OpenApi;
Expand All @@ -13,4 +16,40 @@
.AddOpenApiDefinitionStorage(storage)
.AddBasicServer();
}

[Fact]
public async Task AddGraphQLTransformer_Should_ResolveSchemaName_When_SingleNamedSchemaRegistered()
{
// arrange
var storage = new TestOpenApiDefinitionStorage(
"""
query GetUsers @http(method: GET, route: "/users") {
usersWithoutAuth {
id
}
}
""");
var builder = new WebHostBuilder()

Check warning on line 32 in src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/OpenApi/OpenApiIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.OpenApi.Tests

'WebHostBuilder' is obsolete: 'WebHostBuilder is deprecated in favor of HostBuilder and WebApplicationBuilder. For more information, visit https://aka.ms/aspnet/deprecate/004.' (https://aka.ms/aspnet/deprecate/004)
.ConfigureServices(services =>
{
services.AddRouting();
services.AddGraphQLServer("NamedSchema")
.AddOpenApiDefinitionStorage(storage)
.AddBasicServer();
services.AddOpenApi(options => options.AddGraphQLTransformer());
})
.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapOpenApi());
});
using var server = new TestServer(builder);

Check warning on line 46 in src/HotChocolate/Adapters/test/Adapters.OpenApi.Tests/OpenApi/OpenApiIntegrationTests.cs

View workflow job for this annotation

GitHub Actions / Run HotChocolate.Adapters.OpenApi.Tests

'TestServer.TestServer(IWebHostBuilder)' is obsolete: 'IWebHost, which this method uses, is obsolete. Use one of the ctors that takes an IServiceProvider instead. For more information, visit https://aka.ms/aspnet/deprecate/008.' (https://aka.ms/aspnet/deprecate/008)
var client = server.CreateClient();

// act
var document = await GetOpenApiDocumentAsync(client);

// assert
Assert.Contains("/users", document);
}
}
Loading