MCP越来越火了,各大模型公司也在陆陆续续支持MCP了,OpenAI在前不久声明对MCP的支持,同时社区的SDK也来了,今天就用ModelContextProtocol来创建服务端和客户端,并且找通他们。与此同时,也不能落下SK,看看SK怎么使用MCP。先看Server端:项目文件如下:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.2" />
</ItemGroup>
</Project>
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";
try
{
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使用:项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.3.0-preview.1.25161.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.0-preview.2.25163.2" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.44.0" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="1.44.0-alpha" />
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.2" />
<PackageReference Include="ModelContextProtocol-SemanticKernel" Version="0.0.1-preview-03" />
</ItemGroup>
</Project>
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还添加当前时间插件,看蓝色框,取的是当前时间,正确。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/426691.html