Semantic Kernel:开启MCP

360影视 欧美动漫 2025-04-04 08:50 2

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

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

先看Server端:

项目文件如下:

net10.0 enable enable

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 QueryList(DateTime? beginTime, DateTime? endTime) { Console.WriteLine("参数"); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine($"BeginTime:{beginTime},EndTime:{endTime}"); Console.ResetColor; if (beginTime is || endTime is ) { beginTime = DateTime.Now; endTime = DateTime.Now; } return new List { 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 = ; SseResponseStreamTransport? transport = ; var loggerFactory = endpoints.ServiceProvider.GetRequiredService; var mcpServerOptions = endpoints.ServiceProvider.GetRequiredService>; 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"; try { await transport.RunAsync(requestAborted); } catch (OperationCanceledException) when (requestAborted.IsCancellationRequested) { Console.WriteLine("closed"); } }); routeGroup.MapPost("/message", async context => { if (transport is ) { await Results.BadRequest("Connect to the /sse endpoint before sending messages.").ExecuteAsync(context); return; } var message = await context.Request.ReadFromJsonAsync(McpJsonUtilities.DefaultOptions, context.RequestAborted); if (message is ) { 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使用:

项目文件:

Exe net10.0 enable enable

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、退出"); var no = Console.ReadLine; switch (no) { case "1": await MCPClientToolsListAsync; break; case "2":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; 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还添加当前时间插件,看蓝色框,取的是当前时间,正确。

来源:opendotnet

相关推荐