当前位置: 首页 > news >正文

.NET 创建MCP使用大模型对话

一:准备工作

使用官方C# sdk:https://github.com/modelcontextprotocol/csharp-sdk

版本:dotnet add package ModelContextProtocol --version 0.1.0-preview.4

* 注意 preview版本迭代比较快,方法名、参数都有可能变动,甚至意外BUG,本示只保证使用0.1.0-preview.4版本复现功能。

VS2022版本: 17.13.3

.NET 版本:9.0.201

二:创建MCPServer

我们创建一个天气服务。

 新建控制台项目,选择.NET9框架,名称叫做MCPServer。

添加ModelContextProtocol引用,注意当前是preview版本,需要勾选包含发行版才能搜到。

在Program.cs 文件中添加下述代码,注册McpServer

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
    consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services
    //Mcp服务
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();
await builder.Build().RunAsync();

新增一个天气Tool文件,命名为:WeatherTool,增加下述代码

using ModelContextProtocol.Server;
using System.ComponentModel;

namespace MCPServer
{
    [McpServerToolType]
    public class WeatherTool
    {
        [McpServerTool(Name = "Get City Weather"), Description("获取指定城市的天气,返回temperature温度和weather天气情况组成的json信息。")]
        public static string GetCurrentWeather([Description("城市名称")] string city)
        {
            //随机温度
            var temperature = new Random().Next(-20, 50);
            //天气组
            var weatherList = new string[] { "晴", "多云", "大雨", "小雨", "大雪" };
            //随机天气
            var weather = weatherList[new Random(Guid.NewGuid().GetHashCode()).Next(0, weatherList.Length - 1)];

            //模仿json格式返回
            return "{\"temperature\":" + temperature + ",\"weather\":\"" + weather + "\"}";

        }
    }
}

使用McpServerToolType和McpServerTool对类和方法进行标识。preview早期版本命名为McpToolType和McpTool,注意分辨。

到此,MCPServer编写完成,运行不报错即可。

[可选]调试工具:

在MCPServer项目根目录执行node.js命令,可以打开mcp调试web页:

npx @modelcontextprotocol/inspector dotnet run

打开http://localhost:5173/,并点击链接,需要等一会

连接成功后,点击Tools页面,ListTools可以查看目前注册的Tool。点击相应Tool,可以进行调试,如下图:

如果点击链接报错,没有出现"Connected",你可以手动重新生成一下MCPServer项目,看看是否会报错。有可能项目被某些进程占用了,使用taskkill /pid 进程id /f 杀掉即可。

调试窗口不使用后,建议Ctrl+C杀掉,提示Terminate batch job (Y/N)? 输入Y即可。

三:创建McpClient

新建控制台项目,选择.NET9框架,名称叫做MCPClient。

依然添加ModelContextProtocol引用

1. 注册Client

McpClientOptions options = new()
{
    ClientInfo = new() { Name = "Weather Client", Version = "1.0.0" }
};

//1:注册MCPServer,以项目中引用为例。

var config = new McpServerConfig
{
    Id = "weather",
    Name = "Weather MCP Server",
    TransportType = TransportTypes.StdIo,

     //此处注册McpSever
    TransportOptions = new Dictionary<string, string>
    {
        //当前以项目内部直接运行为例
        ["command"] = "dotnet",
        ["arguments"] = "run --project ../../../../MCPServer --no-build",
    }
};

//创建Client

await using var mcpClient = await McpClientFactory.CreateAsync(config, options);

//查找McpServer中注册的Tools
var mcpTools = await mcpClient.ListToolsAsync();
foreach (var tool in mcpTools)
{
    Console.WriteLine($"{tool.Name} ({tool.Description})");
}

Console.WriteLine("---------- Tools");
Console.WriteLine();

2:注册大模型

方案1,使用本地大模型。示例,使用Ollama 下载的qwq大模型。

添加:Microsoft.Extensions.AI.Ollama程序包,当前示例版本:9.3.0-preview.1.25161.3

//注册大模型
var openClient = new OllamaChatClient(new Uri("http://localhost:11434/"), "qwq:32b");

确保端口是畅通状态,建议先在浏览器打开上述http网址,如果是局域网、广域网,注意配置局域网内可以访问策略,此处不做太多赘述。

方案2,使用远程模型,如阿里百炼平台、华为、腾讯等,此处以阿里百炼(https://bailian.console.aliyun.com/)为例。

添加:Microsoft.Extensions.AI.OpenAI程序包,当前示例版本:9.3.0-preview.1.25161.3

var oclinet = new OpenAIClient(new System.ClientModel.ApiKeyCredential("密钥"), new OpenAIClientOptions
{
    //阿里云提供的基础地址
    Endpoint = new Uri("https://dashscope.aliyuncs.com/compatible-mode/v1")
});
//模型名称
var openClient = new OpenAIChatClient(oclinet, "qwen-max");

无论使用本地还是远程大模型,创建成功后先测试一下:

//测试模型,使用流式输出。
var res = openClient.GetStreamingResponseAsync("你好");
await foreach (var message in res)
{
    Console.Write(message);
}
Console.WriteLine();
Console.WriteLine("-------------llm test");

返回示例:

到此,连接大模型成功。

3:注册ChatClient

var client = new ChatClientBuilder(openClient)
    //添加日志
    .UseLogging(factory)
    //向聊天客户端添加函数调用
    .UseFunctionInvocation()
    .Build();

4:执行大模型对话

下述代码比较简单,就是循环接收输入,然后执行大模型对话输出,不做太多解释。


var msg = "";

while (true)
{
    Console.WriteLine();
    Console.WriteLine("这里是天气服务,你想咨询哪里的天气?");
    msg = Console.ReadLine();

    if (msg == "exit")
    {
        Console.WriteLine("程序退出");
        return;
    }

    IList<ChatMessage> messages =
    [
        //为ai设定身份
        new(ChatRole.System, """
                             你是一个天气助理,在输出天气时,请以家长口吻叮嘱用户添衣、带伞等。
                             """),
        new(ChatRole.User, msg)
    ];

    //区别于GetStreamingResponseAsync,此处示例非流式输出
    //注意,某些大模型要求流水输出,只能使用GetStreamingResponseAsync方式。
    var response =
    await client.GetResponseAsync(
        messages,
        new ChatOptions { Tools = [.. mcpTools] });

    Console.WriteLine(response);

}

注意点1:使用ChatRole.System设定ai角色。

注意点2:使用 GetStreamingResponseAsync 流模式接收推理大模型,使用GetResponseAsync接收普通模型。有些模型不支持GetResponseAsync方式,只支持GetStreamingResponseAsync方式,注意区分。比如下图所示:

5:执行程序

输入北京

拿到tool的回答,气温20度,大雨。

大模型根据天气及角色定义,给出最后的回答,到此结束。

以下是源码:

MCPServer.Program.cs

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
    consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();
await builder.Build().RunAsync();

MCPServer.WeatherTool.cs

using ModelContextProtocol.Server;
using System.ComponentModel;

namespace MCPServer
{
    [McpServerToolType]
    public class WeatherTool
    {
        [McpServerTool(Name = "Get City Weather"), Description("获取指定城市的天气,返回temperature温度和weather天气情况组成的json信息。")]
        public static string GetCurrentWeather([Description("城市名称")] string city)
        {
            //随机温度
            var temperature = new Random().Next(-20, 50);
            //天气组
            var weatherList = new string[] { "晴", "多云", "大雨", "小雨", "大雪" };
            //随机天气
            var weather = weatherList[new Random(Guid.NewGuid().GetHashCode()).Next(0, weatherList.Length - 1)];

            //模仿json格式返回
            return "{\"temperature\":" + temperature + ",\"weather\":\"" + weather + "\"}";

        }
    }
}

MCPClient.Program.cs

using Microsoft.Extensions.AI;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Client;
using ModelContextProtocol.Configuration;
using ModelContextProtocol.Protocol.Transport;
using OpenAI;

Console.WriteLine($"程序启动中,请稍后");

McpClientOptions options = new()
{
    ClientInfo = new() { Name = "Weather Client", Version = "1.0.0" }
};

//1:注册MCPServer,以项目中引用为例。

var config = new McpServerConfig
{
    Id = "weather",
    Name = "Weather MCP Server",
    TransportType = TransportTypes.StdIo,
    TransportOptions = new Dictionary<string, string>
    {
        //运行MCPServer
        ["command"] = "dotnet",
        ["arguments"] = "run --project ../../../../MCPServer --no-build",
    }
};


using var factory =
    LoggerFactory.Create(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Trace));

//2:创建MCPClient
await using var mcpClient = await McpClientFactory.CreateAsync(config, options);


//3:发现MCPServer中的Tool
var mcpTools = await mcpClient.ListToolsAsync();
foreach (var tool in mcpTools)
{
    Console.WriteLine($"{tool.Name} ({tool.Description})");
}

Console.WriteLine("---------- Tools");
Console.WriteLine();


//4:注册大模型

//注册方式1,使用本地模型。以本地使用Ollama启动的千问32b模型为例
//var openClient = new OllamaChatClient(new Uri("http://localhost:11434/"), "qwq:32b");

//注册方式2,使用远程模型。以阿里云百炼平台为例
var oclinet = new OpenAIClient(new System.ClientModel.ApiKeyCredential("sk-密钥"), new OpenAIClientOptions
{
    Endpoint = new Uri("https://dashscope.aliyuncs.com/compatible-mode/v1")
});
//模型名称
var openClient = new OpenAIChatClient(oclinet, "qwen-max");

//测试模型,使用流式输出。
var res = openClient.GetStreamingResponseAsync("你好");
await foreach (var message in res)
{
    Console.Write(message);
}
Console.WriteLine();

Console.WriteLine("-------------llm test");
Console.WriteLine();


//5:创建Chat客户端
var client = new ChatClientBuilder(openClient)
    //添加日志
    .UseLogging(factory)
    //向聊天客户端添加函数调用
    .UseFunctionInvocation()
    .Build();

//6:执行对话
var msg = "";

while (true)
{
    Console.WriteLine();
    Console.WriteLine("这里是天气服务,你想咨询哪里的天气?");
    msg = Console.ReadLine();

    if (msg == "exit")
    {
        Console.WriteLine("程序退出");
        return;
    }

    IList<ChatMessage> messages =
    [
        //为ai设定身份
        new(ChatRole.System, """
                             你是一个天气助理,在输出天气时,请以家长口吻叮嘱用户添衣、带伞等。
                             """),
        new(ChatRole.User, msg)
    ];

    //区别于GetStreamingResponseAsync,此处示例非流式输出
    //注意,某些大模型要求流水输出,只能使用GetStreamingResponseAsync方式。
    var response =
    await client.GetResponseAsync(
        messages,
        new ChatOptions { Tools = [.. mcpTools] });

    Console.WriteLine(response);

}

代码仓库:https://github.com/zhanglilong23/mcpdemo.git

http://www.dtcms.com/a/106648.html

相关文章:

  • 【计网速通】计算机网络核心知识点与高频考点——数据链路层(二)
  • kafka消息可靠性传输语义
  • 大语言模型开发框架——LangChain
  • 使用PyTorch实现LeNet-5并在Fashion-MNIST数据集上训练
  • 【Linux】内核驱动学习笔记(二)
  • 基于Spring AI与Ollama构建本地DeepSeek对话机器人
  • 数据库分库分表中间件及对比
  • ensp 网络模拟器 思科华为基于VLANIF的公司网络搭建
  • 2025.4.2总结
  • Go语言GC:三色标记法工程启示|Go语言进阶(3)
  • K-means算法
  • 从零搭建微服务项目Pro(第7-1章——分布式雪花算法)
  • cmake(11):list 选项 排序 SORT,定义宏 add_definitions,cmake 里预定义的 8 个宏
  • Git 命令大全:通俗易懂的指南
  • 基于大模型预测风湿性心脏病二尖瓣病变的多维度诊疗研究报告
  • 内网隔离环境下Java实现图片预览的三大解决方案
  • 【Django开发】前后端分离django美多商城项目第15篇:商品搜索,1. Haystack介绍和安装配置【附代码文档】
  • 从 ZStack 获取物理机与云主机信息并导出 Excel 文件
  • visual studio 2022的windows驱动开发
  • C# System.Text.Json 中 JsonIgnoreCondition 使用详解
  • Linux2 CD LL hostnamectl type mkdir dudo
  • 跨系统平台实践:在内网自建kylin服务版系统yum源
  • 面基JavaEE银行金融业务逻辑层处理金融数据类型BigDecimal
  • AI提示词:好评生成器
  • 鸿蒙NEXT小游戏开发:数字华容道
  • 详解相机的内参和外参,以及内外参的标定方法
  • 背包DP总结
  • GO语言 使用protobuf
  • 【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【代码篇】A题解题全流程(持续更新)
  • 全国产ADC 16bit 2通道1G采样 双FMC子板