大家好,我是Edison。

近日被MCP刷屏了,刚好看到张队发了一篇文章提到MCP的官方C# SDK发布了预览版,于是手痒痒尝了一下鲜,写了一个DEMO分享给大家。

MCP是什么鬼?

MCP,全称是“模型上下文协议”(Model Context Protocol),是Anthropic开源的一个标准协议。打个比方,它就像是AI世界的“USB-C”接口。你知道USB-C吧?一根线就能连接手机、电脑、充电器,超级方便。MCP的作用也差不多,它让AI模型(比如Anthropic的Claude)可以轻松地跟外部的数据源和工具连接起来,比如数据库、文件系统、API等等。以前,如果想让AI访问你的数据库或者调用某个工具,得专门写一堆代码,特别麻烦。现在有了MCP,就像是插上USB-C线那么简单,AI模型通过这个标准协议就能直接获取数据或执行操作,不用每次都重新开发连接方式。这样,开发AI应用就变得更快、更省事了。

MCP是如何工作的?

MCP是一个典型的C/S架构模式,即客户端 和 服务端,它们之间采用一种标准的消息格式(JSON-RPC)进行通信,大模型可以通过这些消息进行:

(1)获取数据:例如通过SQL从DB中查询订单数据;

(2)执行操作:例如通过API调用发个消息通知;

(3)理解指令:例如通过一些提示词模板,LLM可以知道如何使用数据和工具;

简单来说,MCP就是AI的“万能接口”。有了它,AI模型就能像插上USB-C线一样,轻松连接到各种外部数据源和工具,变得更聪明、更实用。不管是开发者还是普通用户,都能通过MCP让AI干更多事,而且过程简单又安全。未来随着MCP的普及,我们可能会看到更多能干实事儿的AI应用冒出来!

创建一个MCP Server

这里我们使用MCP C# SDK来实现,使用标准的IO传输方式。

(1)创建一个.NET 8.0控制台应用,假设命名为:EDT.McpServer.ConsoleHost

(2)安装MCP SDK

ModelContextProtocol 0.1.0-preview.4

(3)创建一个Tools目录,然后添加一个TimeTool.cs

using ModelContextProtocol.Server;
using System.ComponentModel; namespace EDT.McpServer.Tools.ConsoleHost; [McpServerToolType]
public static class TimeTool
{
[McpServerTool, Description("Get the current time for a city")]
public static string GetCurrentTime(string city) =>
$"It is {DateTime.Now.Hour}:{DateTime.Now.Minute} in {city}.";
}

这个TimeTool就是我们定义的基于MCP的Tool,可以看到基于SDK提供的Attribute,可以方便地将其指定为MCP Server Tools。

(3)修改Program.cs设置为启动MCP Server

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using EDT.McpServer.Tools.ConsoleHost; try
{
Console.WriteLine("Starting MCP Server..."); var builder = Host.CreateEmptyApplicationBuilder(settings: null);
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly(); await builder.Build().RunAsync();
return 0;
}
catch (Exception ex)
{
Console.WriteLine($"Host terminated unexpectedly : {ex.Message}");
return 1;
}

同样,也是很方便地就完成了MCP Server的创建,重点关注WithToolsFromAssembly这个扩展方法,它会扫描程序集中添加了McpServerTool标签的类进行注册。

这时我们已经完成了MCP Server的创建,可以把它启动起来了。

但是,要完成今天的目标,连接起来测试,我们还得实现一个Client来调用Server。

创建一个MCP Client

(1)创建一个.NET 8.0控制台应用,假设命名为:EDT.McpServer.Client

(2)安装MCP SDK

ModelContextProtocol 0.1.0-preview.4

(3)修改Program.cs,实现以下步骤:

创建MCP Client:

await using var mcpClient = await McpClientFactory.CreateAsync(new()
{
Id = "time",
Name = "Time MCP Server",
TransportType = TransportTypes.StdIo,
TransportOptions = new()
{
["command"] = @"..\..\..\..\EDT.McpServer\bin\Debug\net8.0\EDT.McpServer.exe"
}
});

需要注意的是:这里我们MCP Server使用的是标准IO传输方式,因此指定TransportType为StdIo,同时指定command为MCP Server应用程序所在的exe的目录位置。当然,这里的这种方式有点不是很规范,但你只需要了解它是需要访问MCP Server的程序地址就行了。

列出可用的Tools:

var tools = await mcpClient.ListToolsAsync();
foreach (var tool in tools)
{
Console.WriteLine($"{tool.Name} ({tool.Description})");
}

直接执行Tool:(一般情况下不会这样用,而是在LLM中来调用)

var result = await mcpClient.CallToolAsync(
"GetCurrentTime",
new Dictionary<string, object?>() { ["city"] = "Chengdu" },
CancellationToken.None);
Console.WriteLine(result.Content.First(c => c.Type == "text").Text);

通过LLM来调用Tool:这里基于Microsoft.Extensions.AI核心库来实现的,你也可以用Semantic Kernel库来做这个事,都行!

var apiKeyCredential = new ApiKeyCredential(config["LLM:ApiKey"]);
var aiClientOptions = new OpenAIClientOptions();
aiClientOptions.Endpoint = new Uri(config["LLM:EndPoint"]);
var aiClient = new OpenAIClient(apiKeyCredential, aiClientOptions)
.AsChatClient(config["LLM:ModelId"]);
var chatClient = new ChatClientBuilder(aiClient)
.UseFunctionInvocation()
.Build();
IList<ChatMessage> chatHistory =
[
new(ChatRole.System, """
You are a helpful assistant delivering time in one sentence
in a short format, like 'It is 10:08 in Paris, France.'
"""),
];
// Core Part: Get AI Tools from MCP Server
var mcpTools = await mcpClient.ListToolsAsync();
var chatOptions = new ChatOptions()
{
Tools = [..mcpTools]
};
// Prompt the user for a question.
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Assistant> How can I assist you today?");
while (true)
{
// Read the user question.
Console.ForegroundColor = ConsoleColor.White;
Console.Write("User> ");
var question = Console.ReadLine();
// Exit the application if the user didn't type anything.
if (!string.IsNullOrWhiteSpace(question) && question.ToUpper() == "EXIT")
break; chatHistory.Add(new ChatMessage(ChatRole.User, question));
Console.ForegroundColor = ConsoleColor.Green;
var response = await chatClient.GetResponseAsync(chatHistory, chatOptions);
var content = response.ToString();
Console.WriteLine($"Assistant> {content}");
chatHistory.Add(new ChatMessage(ChatRole.Assistant, content)); Console.WriteLine();
}

最后的效果如下图所示:

创建一个基于ASP.NET的MCP Server

除了使用标准的IO协议,我们还可以实现一个基于ASP.NET Core的MCP SSE Server,顾名思义它就是使用SSE传输方式。

(1)创建一个.NET 8.0 ASP.NET WebAPI应用,假设命名为:EDT.McpServer.WebHost

(2)安装MCP SDK

ModelContextProtocol 0.1.0-preview.4
ModelContextProtocol.AspNetCore 0.1.0-preview.4

(3)创建一个Tools目录,然后添加一个TimeTool.cs

这里和上面的一样,不再赘述。

(4)修改Program.cs完成MCP Server配置:

using EDT.McpServer.WebHost.Tools;
using ModelContextProtocol.AspNetCore; try
{
Console.WriteLine("Starting MCP Server..."); var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpServer().WithToolsFromAssembly();
var app = builder.Build(); app.UseHttpsRedirection();
app.MapGet("/", () => "Hello MCP Server!");
app.MapMcp(); app.Run();
return 0;
}
catch (Exception ex)
{
Console.WriteLine($"Host terminated unexpectedly : {ex.Message}");
return 1;
}

可以看到,就是这么简单,通过MapMcp实现了/sse端点的映射。后续MCP Client要连接的就是这个/sse的端点。

(5)这时,你就可以把这个ASP.NET WebAPI应用启动起来,假设我们这里是 https://localhost:8443,你就可以通过下面的一点点修改,让之前的这个MCP Client连接上这个MCP Server:

await using var mcpClient = await McpClientFactory.CreateAsync(new()
{
Id = "time",
Name = "Time MCP Server",
TransportType = TransportTypes.Sse,
Location = "https://localhost:8443/sse"
});

可以看到,仅仅修改TransportType为SSE,然后指定Server的BaseUrl即可。

OK,让我们再来运行一下Client看看能否再次成功调用Tool:

看来这次使用SSE传输方式也能调用成功了!Perfect!

小结

本文介绍了MCP的基本概念和工作模式,然后演示了如何通过MCP C# SDK创建MCP Server和Client,以及基于ASP.NET WebAPI创建SSE Server,相信会对你有所帮助。

如果你也是.NET程序员希望参与AI应用的开发,那就快快了解和使用基于Microsoft.Extensioins.AI + MCP C# SDK 的生态组件库吧。

示例源码

GitHub:点此查看

参考内容

MCP C# SDK Samples 《MCP C# Sample Demos

推荐内容

Microsoft Learn

eShopSupport

devblogs

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

使用MCP C# SDK开发MCP Server + Client的更多相关文章

  1. Sentry 开发者贡献指南 - SDK 开发(性能监控)

    内容整理于官方开发文档 系列 Docker Compose 部署与故障排除详解 K8S + Helm 一键微服务部署 Sentry 开发者贡献指南 - 前端(ReactJS生态) Sentry 开发者 ...

  2. 高拍仪拍照SDK开发(良田影像S300L|S500L)

    高拍仪拍照SDK开发下载地址:点击下载 本SDK适用于:良田影像S300L|S500L 高拍仪如图: SDN开发包安装之后找到安装目录,如图: 大家找到各自需要的版本即可,需要注意的是如果需要上传图片 ...

  3. Vmware Vsphere WebService SDK开发(第一讲)-基本知识学习

    刚开始这方面开发的时候,不知道如何下手,能够查到的资料特别少,而且看到很多网友和我一样也在找这方面的资料.接下来的一段时间我就结合自己所参与的项目,完成关于Vmware Vsphere WebServ ...

  4. 搭建带热更新功能的本地开发node server

    引言 使用webpack有一段时间了,对其中的热更新的大概理解是:对某个模块做了修改,页面只做局部更新而不需要刷新整个页面来进行更新.这样就能节省因为整个页面刷新所产生开销的时间,模块热加载加快了开发 ...

  5. Android SDK 开发——发布使用踩坑之路

    前言 在 Android 开发过程中,有些功能是通用的,或者是多个业务方都需要使用的. 为了统一功能逻辑及避免重复开发,因此将该功能开发成一个 SDK 是相当有必要的. 背景 刚好最近自己遇到了类似需 ...

  6. 16-ESP8266 SDK开发基础入门篇--TCP 服务器 非RTOS运行版,串口透传(串口回调函数处理版)

    https://www.cnblogs.com/yangfengwu/p/11105466.html 其实官方给的RTOS的版本就是在原先非RTOS版本上增加的 https://www.cnblogs ...

  7. Android SDK 开发指南

    Android SDK 开发指南 视频详解 以下视频是对融云 Android SDK 开发使用的详细讲解,您可以在阅读文档时配合学习.   更多视频教程如下: CSDN 融云 Android SDK ...

  8. Node.js 从零开发 web server博客项目[express重构博客项目]

    web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...

  9. Sentry 开发者贡献指南 - SDK 开发(事件负载)

    内容整理自官方开发文档 系列 Docker Compose 部署与故障排除详解 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentr ...

  10. nrf52——DFU升级OTA升级方式详解(基于SDK开发例程)

    在我们开始前,默认你已经安装好了一些基础工具,如nrfutil,如果你没有安装过请根据官方中文博客去安装好这些基础工具,连接如下:Nordic nRF5 SDK开发环境搭建(nRF51/nRF52芯片 ...

随机推荐

  1. MySQL-进阶篇

    一.连接查询 图解示意图 1.建表语句 部门和员工关系表: CREATE TABLE `tb_dept` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT ...

  2. 阿里云-物联网IOT

    https://iot.aliyun.com/?spm=5176.23056729.J_3207526240.265.3dcc3f06JR1HG2

  3. LinkedList的源码

    LinkedList LinkedList是通过双向链表去实现的,他的数据结构具有双向链表的优缺点,既然是双向链表,那么的它的顺序访问效率会非常高,而随机访问的效率会比较低,它包含一个非常重要的私有内 ...

  4. Collection接口与其子接口实现类-----总复习

    数组与集合 1. 集合与数组存储数据概述:集合.数组都是对多个数据进行存储操作的结构,简称Java容器.说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi, ...

  5. Oracle数据快照设置

    1.1 手册目的 该手册主要目的是用于生产环境排查问题及恢复用户误操作删除数据及程序错误导致数据丢失使用. 1.2 查看Undo表空间参数 在命令窗口查询Undo表空间的快照参数 1 show par ...

  6. 云安全CIA:关键信息保证的三大支柱

    本文分享自天翼云开发者社区<云安全CIA:关键信息保证的三大支柱>,作者:每日知识小分享 随着云计算的迅速普及,云安全问题越来越受到关注.云安全涉及的范围广泛,涵盖了云端数据中心的物理安全 ...

  7. 【忍者算法】从图书馆编目到数组搜索:探索缺失的第一个正整数|LeetCode 41 缺失的第一个正整数

    从图书馆编目到数组搜索:探索缺失的第一个正整数 生活中的算法 想象你是一位图书馆管理员,正在整理一排连续编号的图书.这些书应该从1号开始按顺序排列,但是有些编号的书不见了.你的任务是找出第一个缺失的编 ...

  8. redis如何设置密码

    密码设置 这里简单介绍一下redis如何设置密码redis密码设置有两种方式,一种需要重启redis服务,一种不需要重启redis服务. 首先,介绍一下需要重启redis服务的设置方式即找到redis ...

  9. linux mint安装hadoop

    一.安装 安装ssh openssh-server   配置jdk环境变量~/.bashrc参考 export JAVA_HOME=/opt/jdk1.7.0_55/ export JRE_HOME= ...

  10. Qt 枚举类型 值、字符串、枚举类型互转

    枚举类型 class Enum : public QObject{ Q_OBJECT public: enum Fruit{ APPLE = 0, BANANA, POTATO } Q_ENUM(Fr ...