前言

网上使用Python创建一个MCP客户端的教程已经有很多了,而使用C#创建一个MCP客户端的教程还很少。

为什么要创建一个MCP客户端呢?

创建了一个MCP客户端之后,你就可以使用别人写好的一些MCP服务了。

效果展示

为了方便大家复现,我没有使用WPF/Avalonia之类的做界面。只是一个简单的控制台程序,可以很容易看懂。

接入了fetch_mcp可以实现获取网页内容了,使用的模型只要具有tool use能力的应该都可以。

我使用的是Qwen/Qwen2.5-72B-Instruct。

开始实践

主要使用的包如下所示:

首先获取MCP服务器:

 private static async Task<IMcpClient> GetMcpClientAsync()
{
DotEnv.Load();
var envVars = DotEnv.Read();
McpClientOptions options = new()
{
ClientInfo = new() { Name = "SimpleToolsConsole", Version = "1.0.0" }
}; var config = new McpServerConfig
{
Id = "test",
Name = "Test",
TransportType = TransportTypes.StdIo,
TransportOptions = new Dictionary<string, string>
{
["command"] = envVars["MCPCommand"],
["arguments"] = envVars["MCPArguments"],
}
}; var factory = new McpClientFactory(
new[] { config },
options,
NullLoggerFactory.Instance
); return await factory.GetClientAsync("test");
}

写死的话就是这样写:

 private static async Task<IMcpClient> GetMcpClientAsync()
{
DotEnv.Load();
var envVars = DotEnv.Read();
McpClientOptions options = new()
{
ClientInfo = new() { Name = "SimpleToolsConsole", Version = "1.0.0" }
}; var config = new McpServerConfig
{
Id = "test",
Name = "Test",
TransportType = TransportTypes.StdIo,
TransportOptions = new Dictionary<string, string>
{
["command"] = node,
["arguments"] = D:/Learning/AI-related/fetch-mcp/dist/index.js,
}
}; var factory = new McpClientFactory(
new[] { config },
options,
NullLoggerFactory.Instance
); return await factory.GetClientAsync("test");
}

重点在:

 TransportOptions = new Dictionary<string, string>
{
["command"] = node,
["arguments"] = D:/Learning/AI-related/fetch-mcp/dist/index.js,
}

用于连接你想连接的MCP服务器。

如果能正确显示你连接mcp服务器提供的工具,说明连接成功。

  var listToolsResult = await client.ListToolsAsync();
var mappedTools = listToolsResult.Tools.Select(t => t.ToAITool(client)).ToList();
Console.WriteLine("Tools available:");
foreach (var tool in mappedTools)
{
Console.WriteLine(" " + tool);
}

开启一个聊天循环:

    Console.WriteLine("\nMCP Client Started!");
Console.WriteLine("Type your queries or 'quit' to exit."); ChatDemo chatDemo = new ChatDemo(); while (true)
{
try
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.Write("\nQuery: ");
string query = Console.ReadLine()?.Trim() ?? string.Empty; if (query.ToLower() == "quit")
break;
if (query.ToLower() == "clear")
{
Console.Clear();
chatDemo.Messages.Clear();
}
else
{
string response = await chatDemo.ProcessQueryAsync(query, mappedTools);
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($"AI回答:{response}");
Console.ForegroundColor = ConsoleColor.White;
}
}
catch (Exception ex)
{
Console.WriteLine($"\nError: {ex.Message}");
}
}
}

处理每次询问:

 public async Task<string> ProcessQueryAsync(string query, List<AITool> tools)
{
if(Messages.Count == 0)
{
Messages =
[
// Add a system message
new(ChatRole.System, "You are a helpful assistant, helping us test MCP server functionality."),
];
} // Add a user message
Messages.Add(new(ChatRole.User, query)); var response = await ChatClient.GetResponseAsync(
Messages,
new() { Tools = tools });
Messages.AddMessages(response);
var toolUseMessage = response.Messages.Where(m => m.Role == ChatRole.Tool); if (toolUseMessage.Count() > 0)
{
var functionMessage = response.Messages.Where(m => m.Text == "").First();
var functionCall = (FunctionCallContent)functionMessage.Contents[1];
Console.ForegroundColor = ConsoleColor.Green;
string arguments = "";
foreach (var arg in functionCall.Arguments)
{
arguments += $"{arg.Key}:{arg.Value};";
}
Console.WriteLine($"调用函数名:{functionCall.Name};参数信息:{arguments}");
foreach (var message in toolUseMessage)
{
var functionResultContent = (FunctionResultContent)message.Contents[0];
Console.WriteLine($"调用工具结果:{functionResultContent.Result}");
} Console.ForegroundColor = ConsoleColor.White;
}
else
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("本次没有调用工具");
Console.ForegroundColor = ConsoleColor.White;
} return response.Text;
}

代码已经放到GitHub,地址:https://github.com/Ming-jiayou/mcp_demo。

将.env-example修改为.env应该就可以运行,如果报错,设置成嵌入的资源即可。

.env配置示例:

API_KEY=sk-xxx
BaseURL=https://api.siliconflow.cn/v1
ModelID=Qwen/Qwen2.5-72B-Instruct
MCPCommand=node
MCPArguments=D:/Learning/AI-related/fetch-mcp/dist/index.js

最后

对C#使用MCP感兴趣的朋友可以关注这个项目:https://github.com/PederHP/mcpdotnet。

有问题欢迎一起交流学习。

使用C#创建一个MCP客户端的更多相关文章

  1. [Swift通天遁地]四、网络和线程-(13)创建一个Socket客户端

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  2. cxf的使用及安全校验-02创建简单的客户端接口

    上一篇文章中,我们已经讲了如果简单的创建一个webservice接口 http://www.cnblogs.com/snowstar123/p/3395568.html 现在我们创建一个简单客户端接口 ...

  3. [Swift通天遁地]四、网络和线程-(14)创建一个Socket服务端

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  4. kubenetes创建一个pod应用

    Pod是可以创建和管理Kubernetes计算的最小可部署单元.一个Pod代表着集群中运行的一个进程.每个pod都有一个唯一的ip. 一个pod类似一个豌豆荚,包含一个或多个容器(通常是docker) ...

  5. 搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

    搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating ...

  6. 一个关于如何创建类似于QQ客户端聊天窗口的模拟小项目

    对于不久之前学习到的一个有关的类似于QQ聊天框的模拟项目,对其中涉及到的知识在这里做一下总结. 首先,你要先创建一个客户端聊天框(取名为:ChatClient,它是你创建的类),这个类继承了Frame ...

  7. 管理员技术(四): 配置NTP网络时间客户端、 创建一个备份包、 配置用户和组账号、配置一个cron任务

    一. 配置NTP网络时间客户端 目标: 本例要求配置虚拟机 server0,能够自动校对系统时间.相关信息如下: 1> NTP服务器位于 classroom.example.com        ...

  8. 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用

    由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...

  9. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  10. Step by Step 创建一个 Web Service

    原创地址:http://www.cnblogs.com/jfzhu/p/4022139.html 转载请注明出处 (一)创建Web Service 创建第一个项目,类型选择ASP.NET Empty ...

随机推荐

  1. APP网站小程序微信登录同步:需要微信公众号、小程序、开放平台打通用户体系(不同主体也行)

    要想APP网站小程序微信登录同步打通用户体系.我们需要将(不同主体也行)多个公众号和小程序都绑定到同一个微信开放平台上,获取到UnionID记录到数据库就可以了. 微信UnionID 机制说明 如果开 ...

  2. Qt/C++摄像头采集/二维码解析/同时采集多路/图片传输/分辨率帧率可调/自动重连

    一.前言 本地摄像头的采集可以有多种方式,一般本地摄像头会通过USB的方式连接,在嵌入式上可能大部分是CMOS之类的软带的接口,这些都统称本地摄像头,和网络摄像头最大区别就是一个是通过网络来通信,一个 ...

  3. Qt通用方法及类库1

    函数名 //桌面宽度高度 static int deskWidth(); static int deskHeight(); //程序文件名称+当前所在路径 static QString appName ...

  4. Spring基础 02 | JdbcTemplate

    JdbcTemplate Spring对Jdbc的Api简单封装 开发步骤 1.导入Spring-jdbc.spring-tx坐标 2.创建数据库表和实例 3.创建jdbcTemplate对象 4.执 ...

  5. 内存吞金兽(Elasticsearch)的那些事儿 -- 数据结构及巧妙算法

    系列目录 内存吞金兽(Elasticsearch)的那些事儿 -- 认识一下 内存吞金兽(Elasticsearch)的那些事儿 -- 数据结构及巧妙算法 内存吞金兽(Elasticsearch)的那 ...

  6. JS播放m3u8

    JS播放m3u8: 利用 hls.min.js <!DOCTYPE html> <html> <head> <title>HLS Video Playb ...

  7. c# 无法捕获 System.NullReferenceException?

    ..在VS debug 模式下会"无法捕获" System.NullReferenceException......但是在release 或者外部运行是能捕获的. test cod ...

  8. 第二章 dubbo源码解析目录

    6.1 如何在spring中自定义xml标签 dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个 ...

  9. w3cschool-微信小程序开发文档-框架

    https://www.w3cschool.cn/weixinapp/1g7f1q8l.html MINA文件结构 文件结构 MINA程序包含一个描述整体程序的app和多个描述各自页面的page. 一 ...

  10. Linux查看当前Cuda(CUDA Toolkit )版本

    纯转载. cat /usr/local/cuda/version.txt nvcc-V nvidia-smi查看的不是当前cuda版本,而是最高支持的cuda版本 https://blog.csdn. ...