MCP越来越火了各大模型公司也在陆陆续续支持MCP

145 阅读2分钟

MCP越来越火了,各大模型公司也在陆陆续续支持MCP了,OpenAI在前不久声明对MCP的支持,同时社区的SDK也来了,今天就用ModelContextProtocol来创建服务端和客户端,并且找通他们。与此同时,也不能落下SK,看看SK怎么使用MCP。

MCP越来越火了,各大模型公司也在陆陆续续支持MCP了,OpenAI在前不久声明对MCP的支持,同时社区的SDK也来了,今天就用ModelContextProtocol来创建服务端和客户端,并且找通他们。与此同时,也不能落下SK,看看SK怎么使用MCP。

先看Server端:

项目文件如下:

Program.cs:

using ModelContextProtocol;

var builder = WebApplication.CreateBuilder(args); builder.Services.AddMcpServer()
.WithStdioServerTransport() .WithToolsFromAssembly(); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.MapMcpSse(); app.Run();

工具定义:

using ModelContextProtocol.Server; using System.ComponentModel;

namespace MCPOrderTool.Tools;

[McpServerToolType] public static class OrderTool [McpServerTool("queryOrder"), Description("按开始日期和结速日期查询订单")] public static List<Order> QueryList(DateTime? beginTime, DateTime? endTime) Console.WriteLine("-------------参数-------------"); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine($"BeginTime:{beginTime},EndTime:{endTime}"); Console.ResetColor(); Console.WriteLine("-------------参数-------------"); if (beginTime is null || endTime is null) beginTime = DateTime.Now; endTime = DateTime.Now; return new List<Order> new Order("NO000001", "Order1", DateTime.Now.ToString("yyyy-MM-dd"), "Pending"), new Order("NO000002", "Order2", DateTime.Now.ToString("yyyy-MM-dd"), "Completed"), new Order("NO000003", "Order3", DateTime.Now.ToString("yyyy-MM-dd"), "Pending"), new Order("NO000004", "Order4", DateTime.Now.ToString("yyyy-MM-dd"), "Completed"), new Order("NO000005", "Order5", DateTime.Now.ToString("yyyy-MM-dd"), "Pending"), new Order("NO000006", "Order6", DateTime.Now.ToString("yyyy-MM-dd"), "Completed"), new Order("NO000007", "Order7", DateTime.Now.ToString("yyyy-MM-dd"), "Pending"), new Order("NO000008", "Order8", DateTime.Now.ToString("yyyy-MM-dd"), "Completed"), new Order("NO000009", "Order9", DateTime.Now.ToString("yyyy-MM-dd"), "Pending"), new Order("NO000010", "Order10", DateTime.Now.ToString("yyyy-MM-dd"), "Completed"),

public record Order(string OrderId, string OrderName, string OrderTime, string OrderStatus);

MCP服务端Map定义:

using ModelContextProtocol.Protocol.Messages; using ModelContextProtocol.Server; using ModelContextProtocol.Utils.Json; using Microsoft.Extensions.Options; using ModelContextProtocol.Protocol.Transport;

public static class McpEndpointRouteBuilderExtensions public static IEndpointConventionBuilder MapMcpSse(this IEndpointRouteBuilder endpoints) IMcpServer? server = null; SseResponseStreamTransport? transport = null; var loggerFactory = endpoints.ServiceProvider.GetRequiredService<ILoggerFactory>(); var mcpServerOptions = endpoints.ServiceProvider.GetRequiredService<IOptions<McpServerOptions>>();

    var routeGroup = endpoints.MapGroup("");

    routeGroup.MapGet("/sse", async (HttpResponse response, CancellationToken requestAborted) =\>
        await using var localTransport = transport = new SseResponseStreamTransport(response.Body);
        await using var localServer = server = McpServerFactory.Create(transport, mcpServerOptions.Value, loggerFactory, endpoints.ServiceProvider);

        await localServer.StartAsync(requestAborted);
        response.Headers.ContentType \= "text/event-stream";
        response.Headers.CacheControl \= "no-cache";
            await transport.RunAsync(requestAborted);
        catch (OperationCanceledException) when (requestAborted.IsCancellationRequested)
            Console.WriteLine("closed");

    routeGroup.MapPost("/message", async context =\>
        if (transport is null)
            await Results.BadRequest("Connect to the /sse endpoint before sending messages.").ExecuteAsync(context);
            return;
        var message = await context.Request.ReadFromJsonAsync<IJsonRpcMessage\>(McpJsonUtilities.DefaultOptions, context.RequestAborted);
        if (message is null)
            await Results.BadRequest("No message in request body.").ExecuteAsync(context);
            return;
        await transport.OnMessageReceivedAsync(message, context.RequestAborted);
        context.Response.StatusCode \= StatusCodes.Status202Accepted;
        await context.Response.WriteAsync("Accepted");
    return routeGroup;

下面是Client使用:

项目文件:

Program.cs文件:

using Azure.Core; using Microsoft.Extensions.AI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Connectors.OpenAI; using ModelContextProtocol.Client; using ModelContextProtocol.Configuration; using ModelContextProtocol.Protocol.Transport; using ModelContextProtocol.Protocol.Types; using ModelContextProtocol.SemanticKernel.Extensions; using ModelContextProtocol.SemanticKernel.Options; using ModelContextProtocol.Server; using OpenAI; using System.ComponentModel; using System.Text.Json; using System.Text.Json.Serialization;

var key = File.ReadAllText("c:/gpt/key.txt");

while (true) Console.WriteLine("==========================================================="); Console.WriteLine("1、获取工具列表 2、Client调用工具 3、SK调用工具 0、退出"); Console.WriteLine("==========================================================="); var no = Console.ReadLine(); switch (no) case "1": await MCPClientToolsListAsync(); break; case "2":

        await MCPClientAsync();
        break;
    case "3":
        await SKClientAsync();
        break;
    case "0":
        return;

async Task MCPClientToolsListAsync() var serverConfig = new McpServerConfig Id = "QueryOrder", Name = "QueryOrder", TransportType = TransportTypes.Sse, Location = "http://localhost:3001/sse" var clientOptions = new McpClientOptions ClientInfo = new() Name = "QueryOrderClient", Version = "0.0.1", var mcpClient = await McpClientFactory.CreateAsync(serverConfig, clientOptions); Console.WriteLine("获取Tools:"); var tools = await mcpClient.ListToolsAsync();

foreach (var tool in tools)

    Console.WriteLine($"{tool.Name},{tool.Description}");
Console.WriteLine();

async Task MCPClientAsync() var serverConfig = new McpServerConfig Id = "QueryOrder", Name = "MCPOrderTool", TransportType = TransportTypes.Sse, Location = "http://localhost:3001/sse" var clientOptions = new McpClientOptions ClientInfo = new() Name = "QueryOrderClient", Version = "0.0.1", var mcpClient = await McpClientFactory.CreateAsync(serverConfig, clientOptions); var functions = await mcpClient.ListToolsAsync(); IChatClient chatClient = new OpenAIClient(key).AsChatClient("gpt-4o-mini") .AsBuilder().UseFunctionInvocation().Build(); var response = chatClient.GetStreamingResponseAsync( "查询本周的订单", new() Tools = [.. functions], await foreach (var item in response) Console.Write(item.Text); Console.WriteLine();

async Task SKClientAsync() var builder = Kernel.CreateBuilder(); builder.Services.AddLogging(c => c.AddDebug().SetMinimumLevel(LogLevel.Trace));

builder.Services.AddOpenAIChatCompletion(
    serviceId: "openai",
    modelId: "gpt-4o-mini",
    apiKey: key);

var kernel = builder.Build();
kernel.Plugins.AddFromType<TimeInformationPlugin\>();
await kernel.Plugins.AddMcpFunctionsFromSseServerAsync("MCPOrderTool", "http://localhost:3001/sse");
var executionSettings = new OpenAIPromptExecutionSettings
    Temperature \= 0,
    FunctionChoiceBehavior \= FunctionChoiceBehavior.Auto()
var prompt = "请查询本月的订单";
var result = kernel.InvokePromptStreamingAsync(prompt, new(executionSettings));
await foreach (var item in result)
    Console.Write(item.ToString());
Console.WriteLine();

public class TimeInformationPlugin [KernelFunction, Description("获取当前的 UTC 时间。")] public string GetCurrentUtcTime() => DateTime.UtcNow.ToString("R");

下面是运行结果:1、列举服务端的工具信息,2、是用普通方式调用MCP服务端,这时注意右边红色的框,时间是2023年,取的是模型时间 3、是用SK的方式调用工具,同时SK还添加当前时间插件,看蓝色框,取的是当前时间,正确。