Browse Source

feat(ai): Add the McpAITool module

pull/1456/head
colin 6 months ago
parent
commit
469ce8c79e
  1. 1
      Directory.Packages.props
  2. 1
      aspnet-core/LINGYUN.MicroService.Aspire.slnx
  3. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs
  4. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/LINGYUN.Abp.MicroService.AIService.csproj
  5. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs
  6. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/Microsoft/Extensions/DependencyInjection/HttpClientHttpAIToolExtenssions.cs
  7. 3
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/FodyWeavers.xml
  8. 30
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/FodyWeavers.xsd
  9. 26
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN.Abp.AI.Tools.Mcp.csproj
  10. 22
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/AbpAIToolsMcpModule.cs
  11. 150
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/McpAIToolDefinitionExtenssions.cs
  12. 46
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/McpAIToolProvider.cs
  13. 18
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/Microsoft/Extensions/DependencyInjection/HttpClientMcpAIToolExtenssions.cs

1
Directory.Packages.props

@ -349,6 +349,7 @@
<PackageVersion Include="NRules" Version="0.9.2" />
<PackageVersion Include="Ocelot.Provider.Polly" Version="20.0.0" />
<PackageVersion Include="OllamaSharp" Version="5.4.20" />
<PackageVersion Include="ModelContextProtocol" Version="1.1.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.74.0-alpha" />
<PackageVersion Include="OpenIddict.Server.DataProtection" Version="7.2.0" />
<PackageVersion Include="OpenIddict.Validation.DataProtection" Version="7.2.0" />

1
aspnet-core/LINGYUN.MicroService.Aspire.slnx

@ -286,6 +286,7 @@
<Project Path="modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj" />
<Project Path="modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN.Abp.AI.Ollama.csproj" Id="d59e459c-7ca2-4c5b-b981-685af7ad2848" />
<Project Path="modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN.Abp.AI.Tools.Http.csproj" Id="d54a5812-80e1-4269-856b-672c23c0a49b" />
<Project Path="modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN.Abp.AI.Tools.Mcp.csproj" Id="a516491e-0862-49aa-8de9-9e23d7f21d3d" />
<Project Path="modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN.Abp.AI.Tools.csproj" Id="49756a42-07d5-4ddd-948e-1e99894a383a" />
<Project Path="modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN.Abp.AIManagement.Application.Contracts.csproj" />
<Project Path="modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN.Abp.AIManagement.Application.csproj" />

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs

@ -1,6 +1,7 @@
using LINGYUN.Abp.AI.Ollama;
using LINGYUN.Abp.AI.Tools;
using LINGYUN.Abp.AI.Tools.Http;
using LINGYUN.Abp.AI.Tools.Mcp;
using LINGYUN.Abp.AIManagement;
using LINGYUN.Abp.AspNetCore.HttpOverrides;
using LINGYUN.Abp.AspNetCore.Mvc.Localization;
@ -23,7 +24,6 @@ using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.IdentityModel.Web;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement.Identity;
@ -53,6 +53,7 @@ namespace LINGYUN.Abp.MicroService.AIService;
typeof(AbpAIOllamaModule),
typeof(AbpAIToolsModule),
typeof(AbpAIToolsHttpModule),
typeof(AbpAIToolsMcpModule),
typeof(AbpAIManagementApplicationModule),
typeof(AbpAIManagementHttpApiModule),
typeof(AIServiceMigrationsEntityFrameworkCoreModule),

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/LINGYUN.Abp.MicroService.AIService.csproj

@ -60,6 +60,7 @@
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AI.Ollama\LINGYUN.Abp.AI.Ollama.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AI.Tools\LINGYUN.Abp.AI.Tools.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AI.Tools.Http\LINGYUN.Abp.AI.Tools.Http.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AI.Tools.Mcp\LINGYUN.Abp.AI.Tools.Mcp.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.Application\LINGYUN.Abp.AIManagement.Application.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.HttpApi\LINGYUN.Abp.AIManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\identity\LINGYUN.Abp.Identity.Session.AspNetCore\LINGYUN.Abp.Identity.Session.AspNetCore.csproj" />

2
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs

@ -61,7 +61,7 @@ public class HttpAITool
var options = Context.ServiceProvider.GetRequiredService<IOptions<AbpAIToolsHttpOptiions>>().Value;
var httpClientFactory = Context.ServiceProvider.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.GetHttpAIToolClient();
var httpClient = httpClientFactory.CreateHttpAIToolClient();
var httpRequestMessage = new HttpRequestMessage(
Context.ToolDefinition.GetHttpMethod(),

2
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/Microsoft/Extensions/DependencyInjection/HttpClientHttpAIToolExtenssions.cs

@ -41,7 +41,7 @@ internal static class HttpClientHttpAIToolExtenssions
return services;
}
public static HttpClient GetHttpAIToolClient(this IHttpClientFactory httpClientFactory)
public static HttpClient CreateHttpAIToolClient(this IHttpClientFactory httpClientFactory)
{
return httpClientFactory.CreateClient(HttpAIToolClient);
}

3
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

26
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN.Abp.AI.Tools.Mcp.csproj

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.AI.Tools.Mcp</AssemblyName>
<PackageId>LINGYUN.Abp.AI.Tools.Mcp</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Http.Client" />
<PackageReference Include="ModelContextProtocol" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.AI.Tools\LINGYUN.Abp.AI.Tools.csproj" />
</ItemGroup>
</Project>

22
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/AbpAIToolsMcpModule.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.AI.Tools.Mcp;
[DependsOn(
typeof(AbpAIToolsModule),
typeof(AbpHttpClientModule))]
public class AbpAIToolsMcpModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMcpAIToolClient();
Configure<AbpAIToolsOptions>(options =>
{
// Mcp工具
options.AIToolProviders.Add<McpAIToolProvider>();
});
}
}

150
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/McpAIToolDefinitionExtenssions.cs

@ -0,0 +1,150 @@
using ModelContextProtocol.Client;
using System;
using System.Collections.Generic;
using Volo.Abp;
namespace LINGYUN.Abp.AI.Tools.Mcp;
public static class McpAIToolDefinitionExtenssions
{
private const string Endpoint = "McpEndpoint";
private const string Headers = "McpHeaders";
private const string TransportMode = "McpTransportMode";
private const string ConnectionTimeout = "McpConnectionTimeout";
private const string MaxReconnectionAttempts = "McpMaxReconnectionAttempts";
private const string CurrentAccessToken = "UseMcpCurrentAccessToken";
public static AIToolDefinition UseMcpCurrentAccessToken(this AIToolDefinition definition, bool useCurrentAccessToken = true)
{
definition.WithProperty(CurrentAccessToken, useCurrentAccessToken);
return definition;
}
public static AIToolDefinition WithMcpEndpoint(this AIToolDefinition definition, string endPoint)
{
Check.NotNullOrWhiteSpace(endPoint, nameof(endPoint));
definition.WithProperty(Endpoint, endPoint);
return definition;
}
public static AIToolDefinition WithMcpTransportMode(this AIToolDefinition definition, HttpTransportMode transportMode = HttpTransportMode.AutoDetect)
{
definition.WithProperty(TransportMode, ((int)transportMode).ToString());
return definition;
}
public static AIToolDefinition WithMcpConnectionTimeout(this AIToolDefinition definition, TimeSpan connectionTimeout)
{
definition.WithProperty(ConnectionTimeout, connectionTimeout.ToString());
return definition;
}
public static AIToolDefinition WithMcpMaxReconnectionAttempts(this AIToolDefinition definition, int maxReconnectionAttempts = 5)
{
definition.WithProperty(MaxReconnectionAttempts, maxReconnectionAttempts);
return definition;
}
public static AIToolDefinition WithMcpHeaders(this AIToolDefinition definition, IDictionary<string, string> headers)
{
Check.NotNullOrEmpty(headers, nameof(headers));
var currentHeaders = definition.GetMcpHeaders();
currentHeaders.AddIfNotContains(headers);
definition.WithProperty(Headers, currentHeaders);
return definition;
}
public static AIToolDefinition WithMcpHeaders(this AIToolDefinition definition, string key, string value)
{
Check.NotNullOrEmpty(key, nameof(key));
Check.NotNullOrEmpty(value, nameof(value));
var currentHeaders = definition.GetMcpHeaders();
currentHeaders.TryAdd(key, value);
definition.WithProperty(Headers, currentHeaders);
return definition;
}
public static bool IsUseMcpCurrentAccessToken(this AIToolDefinition definition)
{
if (definition.Properties.TryGetValue(CurrentAccessToken, out var useCurrentAccessTokenObj) && useCurrentAccessTokenObj != null
&& bool.TryParse(useCurrentAccessTokenObj.ToString(), out var useCurrentAccessToken))
{
return useCurrentAccessToken;
}
return false;
}
public static string GetMcpEndpoint(this AIToolDefinition definition)
{
definition.Properties.TryGetValue(Endpoint, out var endpointObj);
Check.NotNull(endpointObj, nameof(Endpoint));
return endpointObj.ToString()!;
}
public static TimeSpan GetMcpConnectionTimeout(this AIToolDefinition definition, double defaultConnectionTimeoutSeconds = 30)
{
definition.Properties.TryGetValue(ConnectionTimeout, out var connectionTimeoutObj);
if (connectionTimeoutObj != null &&
TimeSpan.TryParse(connectionTimeoutObj.ToString(), out var connectionTimeout))
{
return connectionTimeout;
}
return TimeSpan.FromSeconds(defaultConnectionTimeoutSeconds);
}
public static HttpTransportMode GetMcpTransportMode(this AIToolDefinition definition, HttpTransportMode defaultTransportMode = HttpTransportMode.AutoDetect)
{
definition.Properties.TryGetValue(TransportMode, out var defaultTransportModeObj);
if (defaultTransportModeObj != null &&
Enum.TryParse<HttpTransportMode>(defaultTransportModeObj.ToString(), out var transportMode))
{
return transportMode;
}
return defaultTransportMode;
}
public static int GetMcpMaxReconnectionAttempts(this AIToolDefinition definition, int defaultMaxReconnectionAttempts = 5)
{
definition.Properties.TryGetValue(MaxReconnectionAttempts, out var maxReconnectionAttemptsObj);
if (maxReconnectionAttemptsObj != null &&
int.TryParse(maxReconnectionAttemptsObj.ToString(), out var maxReconnectionAttempts))
{
return maxReconnectionAttempts;
}
return defaultMaxReconnectionAttempts;
}
public static IDictionary<string, string> GetMcpHeaders(this AIToolDefinition definition)
{
if (definition.Properties.TryGetValue(Headers, out var headersObj) && headersObj != null)
{
if (headersObj is IDictionary<string, string> h)
{
return h;
}
}
return new Dictionary<string, string>();
}
}

46
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/McpAIToolProvider.cs

@ -0,0 +1,46 @@
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Tools.Mcp;
public class McpAIToolProvider : IAIToolProvider, ITransientDependency
{
public const string ProviderName = "Mcp";
public string Name => ProviderName;
protected IHttpClientFactory HttpClientFactory { get; }
public McpAIToolProvider(IHttpClientFactory httpClientFactory)
{
HttpClientFactory = httpClientFactory;
}
public async virtual Task<AITool[]> CreateToolsAsync(AIToolDefinition definition)
{
var httpClient = HttpClientFactory.CreateMcpAIToolClient();
var httpClientTransportOptions = new HttpClientTransportOptions
{
Endpoint = new Uri(definition.GetMcpEndpoint()),
AdditionalHeaders = new Dictionary<string, string>(),
TransportMode = definition.GetMcpTransportMode(),
ConnectionTimeout = definition.GetMcpConnectionTimeout(),
MaxReconnectionAttempts = definition.GetMcpMaxReconnectionAttempts(),
};
var headers = definition.GetMcpHeaders();
foreach (var header in headers)
{
httpClientTransportOptions.AdditionalHeaders.TryAdd(header.Key, header.Value);
}
var mcpClient = await McpClient.CreateAsync(
new HttpClientTransport(httpClientTransportOptions, httpClient));
return (await mcpClient.ListToolsAsync()).ToArray();
}
}

18
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/Microsoft/Extensions/DependencyInjection/HttpClientMcpAIToolExtenssions.cs

@ -0,0 +1,18 @@
using System.Net.Http;
namespace Microsoft.Extensions.DependencyInjection;
internal static class HttpClientMcpAIToolExtenssions
{
private const string McpAIToolClient = "__AbpAIMcpToolClient";
public static IServiceCollection AddMcpAIToolClient(this IServiceCollection services)
{
services.AddHttpClient(McpAIToolClient);
return services;
}
public static HttpClient CreateMcpAIToolClient(this IHttpClientFactory httpClientFactory)
{
return httpClientFactory.CreateClient(McpAIToolClient);
}
}
Loading…
Cancel
Save