From 9b5826a6b1b898b6cae6bc9f6328d309f2ad12ba Mon Sep 17 00:00:00 2001 From: ccnetcore Date: Sun, 25 Jan 2026 14:13:24 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=B7=E6=8F=90=E4=BE=9B=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=9A=84=E5=8F=98=E6=9B=B4=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=88=96=E7=AE=80=E8=A6=81=E8=AF=B4=E6=98=8E=EF=BC=88=E4=BE=8B?= =?UTF-8?q?=E5=A6=82=EF=BC=9A=E5=81=9A=E4=BA=86=E4=BB=80=E4=B9=88=E6=94=B9?= =?UTF-8?q?=E5=8A=A8=E3=80=81=E6=B6=89=E5=8F=8A=E5=93=AA=E4=BA=9B=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=EF=BC=89=E3=80=82=20=E6=88=91=E5=B0=86=E6=8C=89?= =?UTF-8?q?=E4=BD=A0=E7=BB=99=E5=AE=9A=E7=9A=84=E8=A7=84=E8=8C=83=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=AF=B9=E5=BA=94=E7=9A=84=E6=8F=90=E4=BA=A4=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=92=8C=E8=AF=B4=E6=98=8E=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Mcp/HttpRequestTool.cs | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/HttpRequestTool.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/HttpRequestTool.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/HttpRequestTool.cs new file mode 100644 index 00000000..81326b4d --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/HttpRequestTool.cs @@ -0,0 +1,143 @@ +using System.ComponentModel; +using System.Text; +using System.Text.Json; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; +using Yi.Framework.AiHub.Domain.Shared.Attributes; + +namespace Yi.Framework.AiHub.Domain.Mcp; + +[YiAgentTool] +public class HttpRequestTool : ISingletonDependency +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + + public HttpRequestTool( + IHttpClientFactory httpClientFactory, + ILogger logger) + { + _httpClientFactory = httpClientFactory; + _logger = logger; + } + + [YiAgentTool("HTTP请求"), DisplayName("HttpRequest"), + Description("发送HTTP请求,支持GET/POST/PUT/DELETE等方法,获取指定URL的响应内容")] + public async Task HttpRequest( + [Description("请求的URL地址")] string url, + [Description("HTTP方法:GET、POST、PUT、DELETE等")] string method = "GET", + [Description("请求体内容(JSON字符串),POST/PUT时使用")] string? body = null, + [Description("请求头,格式:key1:value1,key2:value2")] string? headers = null) + { + if (string.IsNullOrWhiteSpace(url)) + { + return "URL不能为空"; + } + + if (string.IsNullOrWhiteSpace(method)) + { + method = "GET"; + } + + try + { + var client = _httpClientFactory.CreateClient(); + var request = new HttpRequestMessage(new HttpMethod(method.ToUpper()), url); + + // 添加请求体 + if (!string.IsNullOrWhiteSpace(body)) + { + request.Content = new StringContent(body, Encoding.UTF8, "application/json"); + } + + // 添加自定义请求头 + if (!string.IsNullOrWhiteSpace(headers)) + { + AddHeaders(request, headers); + } + + var response = await client.SendAsync(request); + return await FormatResponse(response); + } + catch (Exception ex) + { + _logger.LogError(ex, "HTTP {Method}请求失败: {Url}", method, url); + return $"请求失败: {ex.Message}"; + } + } + + /// + /// 添加请求头 + /// + private void AddHeaders(HttpRequestMessage request, string headers) + { + var headerPairs = headers.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + foreach (var pair in headerPairs) + { + var parts = pair.Split(':', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + if (parts.Length == 2) + { + request.Headers.TryAddWithoutValidation(parts[0], parts[1]); + } + } + } + + /// + /// 格式化响应结果 + /// + private async Task FormatResponse(HttpResponseMessage response) + { + var sb = new StringBuilder(); + sb.AppendLine($"状态码: {(int)response.StatusCode} {response.StatusCode}"); + sb.AppendLine($"Content-Type: {response.Content.Headers.ContentType?.ToString() ?? "未知"}"); + sb.AppendLine(); + + var content = await response.Content.ReadAsStringAsync(); + if (string.IsNullOrWhiteSpace(content)) + { + sb.AppendLine("响应内容为空"); + } + else + { + // 尝试格式化JSON + if (IsJsonContentType(response.Content.Headers.ContentType?.MediaType)) + { + try + { + var jsonDoc = JsonDocument.Parse(content); + sb.AppendLine("响应内容(JSON格式化):"); + sb.AppendLine(JsonSerializer.Serialize(jsonDoc, new JsonSerializerOptions + { + WriteIndented = true + })); + } + catch + { + sb.AppendLine("响应内容:"); + sb.AppendLine(content); + } + } + else + { + sb.AppendLine("响应内容:"); + sb.AppendLine(content); + } + } + + return sb.ToString(); + } + + /// + /// 判断是否为JSON内容类型 + /// + private bool IsJsonContentType(string? contentType) + { + if (string.IsNullOrWhiteSpace(contentType)) + { + return false; + } + + return contentType.Contains("application/json", StringComparison.OrdinalIgnoreCase) || + contentType.Contains("text/json", StringComparison.OrdinalIgnoreCase); + } +}