Commit addd173d authored by shrabbit's avatar shrabbit
Browse files

feat(NetworkTools): 新增 HttpGet 工具发送 HTTP GET 请求,注册到 MCP 服务并添加 RestSharp 依赖

parent 4d01e043
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
        <PackageReference Include="JetBrains.Annotations" Version="2026.2.0" />
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.10" />
        <PackageReference Include="ModelContextProtocol" Version="2.1.0" />
        <PackageReference Include="RestSharp" Version="114.0.0" />
        <PackageReference Include="shRabbit.Base" Version="1.12.1" />
    </ItemGroup>

+3 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ using McpBase.McpServer.Tools;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RestSharp;

var builder = Host.CreateApplicationBuilder(args);

@@ -10,12 +11,14 @@ builder.Logging.AddConsole(o => o.LogToStandardErrorThreshold = LogLevel.Trace);

// Add the MCP services: the transport to use (stdio) and the tools to register.
builder.Services
    .AddSingleton<IRestClient, RestClient>()
    .AddMcpServer(c =>
    {
        
    })
    .WithStdioServerTransport()
    .WithTools<RandomNumberTools>()
    .WithTools<NetworkTools>()
    .WithTools<ProcessState>();

await builder.Build().RunAsync();
 No newline at end of file
+90 −0
Original line number Diff line number Diff line
using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Nodes;
using ModelContextProtocol.Server;
using RestSharp;
using shRabbit.Base;

namespace McpBase.McpServer.Tools;

public class NetworkTools(IRestClient client)
{
    [McpServerTool, Description("send a HTTP GET request.")]
    public async Task<HttpResponse> HttpGet(
        [Description("request url")]string url,
        [Description("request headers(JSON format, like '{\"Content-Type\":\"application/json\"}').")] string headers = "{\"Content-Type\":\"application/json\"}s",
        [Description("timeout(ms)")]int timeout = 15000)
    {
        if (string.IsNullOrEmpty(url))
        {
            return new HttpResponse("URL is empty");
        }

        Dictionary<string, string> headerList = [];
        try
        {
            var json = JsonNode.Parse(headers);
            
            if (json is null)
                return new HttpResponse($"Parse JSON headers error: JSON is null.");

            if (json.GetValueKind() != JsonValueKind.Object)
                return new HttpResponse($"Parse JSON headers error: Root JSON type is not Object.");

            foreach (var kv in json.AsObject())
            {
                if (kv.Value is null)
                    return new HttpResponse($"Parse JSON headers error: JSON key {kv.Key} is null.");

                if (kv.Value.GetValueKind() != JsonValueKind.String)
                    return new HttpResponse($"Parse JSON headers error: JSON key {kv.Key} type is not String.");
                
                headerList[kv.Key] = kv.Value.ToString();
            }
        }
        catch (JsonException ex)
        {
            return new HttpResponse($"Parse JSON headers error: {ex.Message}");
        }

        var request = new RestRequest(url);
        request.AddHeaders(headerList);
        
        var ct = new  CancellationTokenSource(timeout);
        try
        {
            var response = await client.ExecuteAsync(request, ct.Token);
            if (response.IsSuccessful)
            {
                return new HttpResponse
                {
                    StatusCode = (int)response.StatusCode,
                    Content = response.Content,
                    Headers = response.Headers?.ToDictionary(h => h.Name, h => h.Value.ToString()) ?? [],
                    Length = response.ContentLength is null ? "N/A" : new ByteSize(response.ContentLength ?? 0).ToString(),
                    LengthRaw = response.ContentLength ?? -1
                };
            }
            
            return new HttpResponse(response.ErrorMessage ?? response.ErrorException?.Message ?? "Unknown Error.")
            {
                StatusCode = (int)response.StatusCode,
            };
        }
        catch (OperationCanceledException)
        {
            return new HttpResponse("Request timeout");
        }
    }
}

public class HttpResponse(string errorMessage = "No Errors.")
{
    public string ErrorMessage { get; set; } = errorMessage;

    public int StatusCode { get; set; } = -1;
    public string? Content { get; set; } = null;
    public string Length { get; set; } = "N/A";
    public long LengthRaw { get; set; } = -1;
    public Dictionary<string, string> Headers { get; set; } = [];
}
 No newline at end of file