diff --git a/Directory.Packages.props b/Directory.Packages.props index 6da9521f7..a394b1618 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,6 +6,11 @@ 9.7.1 + + + + + @@ -20,6 +25,7 @@ + @@ -29,6 +35,7 @@ + diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs index d651d7ee3..fb587e2af 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs @@ -76,8 +76,8 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions( ConfigureParameterBinding = pi => { if (RequestServiceProvider.IsAugmentedWith(pi.ParameterType) || - (options?.Services?.GetService() is { } ispis && - ispis.IsService(pi.ParameterType))) + (options?.Services?.GetService() is { } serviceProviderIsService && + serviceProviderIsService.IsService(pi.ParameterType))) { return new() { diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs index a8b0d2486..054cbed34 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs @@ -83,8 +83,8 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions( ConfigureParameterBinding = pi => { if (RequestServiceProvider.IsAugmentedWith(pi.ParameterType) || - (options?.Services?.GetService() is { } ispis && - ispis.IsService(pi.ParameterType))) + (options?.Services?.GetService() is { } serviceProviderIsService && + serviceProviderIsService.IsService(pi.ParameterType))) { return new() { diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs index afd3912b6..b3adcd9ac 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs @@ -83,8 +83,8 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions( ConfigureParameterBinding = pi => { if (RequestServiceProvider.IsAugmentedWith(pi.ParameterType) || - (options?.Services?.GetService() is { } ispis && - ispis.IsService(pi.ParameterType))) + (options?.Services?.GetService() is { } serviceProviderIsService && + serviceProviderIsService.IsService(pi.ParameterType))) { return new() { diff --git a/src/ModelContextProtocol/McpServerBuilderExtensions.cs b/src/ModelContextProtocol/McpServerBuilderExtensions.cs index d925b24f6..6fcd9234f 100644 --- a/src/ModelContextProtocol/McpServerBuilderExtensions.cs +++ b/src/ModelContextProtocol/McpServerBuilderExtensions.cs @@ -783,8 +783,18 @@ private static void AddSingleSessionServerDependencies(IServiceCollection servic /// Creates an instance of the target object. private static object CreateTarget( IServiceProvider? services, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) => - services is not null ? ActivatorUtilities.CreateInstance(services, type) : - Activator.CreateInstance(type)!; + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + if (services is null) + { + return Activator.CreateInstance(type)!; + } + + var isService = services.GetService()?.IsService(type) == true; + + return isService + ? services.GetRequiredService(type) + : ActivatorUtilities.CreateInstance(services, type); + } #endregion } diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsCreateTargetHelperTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsCreateTargetHelperTests.cs new file mode 100644 index 000000000..f0e957823 --- /dev/null +++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsCreateTargetHelperTests.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.DependencyInjection; +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; +using System.ComponentModel; + +namespace ModelContextProtocol.Tests.Configuration; + +public class McpServerBuilderExtensionsCreateTargetHelperTests(ITestOutputHelper testOutputHelper) + : ClientServerTestBase(testOutputHelper) +{ + private const string ToolName = "Pets Service"; + private const string BaseAddress = "https://localhost:7387/pets"; + + protected override void ConfigureServices(ServiceCollection services, IMcpServerBuilder mcpServerBuilder) + { + mcpServerBuilder.WithTools(); + + services.AddHttpClient(client => + { + client.BaseAddress = new Uri(BaseAddress); + }); + } + + /// + /// Verifies that a typed HttpClient registered in DI is correctly injected into a server tool + /// and used by the tool implementation. This test covers the scenario described in + /// https://github.com/modelcontextprotocol/csharp-sdk/issues/685. + /// + [Fact] + public async Task Typed_HttpClient_Is_Used_By_Tool() + { + // Arrange + await using var client = await CreateMcpClientForServer(); + + // Act + var result = await client.CallToolAsync(ToolName, cancellationToken: TestContext.Current.CancellationToken); + + // Assert + Assert.NotNull(result.Content); + Assert.NotEmpty(result.Content); + + var text = (result.Content[0] as TextContentBlock)?.Text; + Assert.Equal(BaseAddress, text); + } + + [McpServerToolType] + private sealed class PetsService(HttpClient httpClient) + { + [McpServerTool(Name = ToolName)] + [Description("List all pets")] + public string GetBaseAddress() + { + // Returning HttpClient.BaseAddress for verification + return httpClient.BaseAddress?.ToString() ?? string.Empty; + } + } +} diff --git a/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj b/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj index 993564bf0..46a5b02e6 100644 --- a/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj +++ b/tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj @@ -43,6 +43,7 @@ +