C#实现MCP Client 与 LLM 连接,抓取网页内容功能!
前面的课程,我们已经用C#实现了,自己的MCP Client。
下面我们一起来实现,MCP Client与LLM 对接。
一、添加依赖库
目前来说,绝大部分的大模型的API,都是遵循OpenAI的接口规范。
Microsoft.Extensions.AI 是微软官方提供的一套 统一的 AI 抽象层 ,大大简化 AI 模型在 .NET 应用中的集成。
添加依赖库:Microsoft.Extensions.AI.OpenAI,版本为:最新预发行版 9.4.4-preview.1.25259.16,添加的时候记得勾选:包括预发行版。

添加依赖库:Microsoft.Extensions.AI,版本为:9.4.4-preview.1.25259.16。

二、OpenAI 客户端实现
新增文件:ChatAIClient

2.1 初始化OpenAI客户端
初始化OpenAI客户端,并使用UseFunctionInvocation 来增强客户端, 这里启用函数调用。
备注:以下代码涉及的秘钥,记得替换为自己的。
using Microsoft.Extensions.AI;
using OpenAI;
using System.ClientModel;
namespace MCPClient
{
/// <summary>
/// 表示一个用于与 AI 聊天模型交互的客户端封装类。
/// 负责初始化聊天客户端并维护对话上下文。
/// </summary>
public class ChatAIClient
{
/// <summary>
/// 封装后的 AI 聊天客户端接口,支持函数调用等功能。
/// </summary>
private IChatClient ChatClient;
/// <summary>
/// 存储当前会话中的所有聊天消息记录。
/// </summary>
private IList<ChatMessage> Messages;
/// <summary>
/// API 访问密钥,用于身份认证。【记得替换为自己的】
/// </summary>
private const string _apiKey = "6092598c-ce00-48fd-a5be-0d758088c888";
/// <summary>
/// AI 服务的基础请求地址。【记得替换为自己的】
/// </summary>
private const string _baseURL = "https://api-inference.modelscope.cn/v1/";
/// <summary>
/// 使用的 AI 模型标识符。【记得替换为自己的】
/// </summary>
private const string _modelID = "Qwen/Qwen2.5-72B-Instruct";
/// <summary>
/// 初始化一个新的 <see cref="ChatAIClient"/> 实例。
/// 构造函数中自动完成聊天客户端的初始化配置。
/// </summary>
public ChatAIClient()
{
InitIChatClient();
}
/// <summary>
/// 初始化内部使用的 AI 聊天客户端实例。
/// 配置 API 凭证、服务端点,并构建具备函数调用能力的客户端。
/// 同时初始化系统消息作为对话起点。
/// </summary>
private void InitIChatClient()
{
// 创建 API 密钥凭证
ApiKeyCredential apiKeyCredential = new ApiKeyCredential(_apiKey);
// 设置 OpenAI 客户端选项,如自定义服务端点
OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
openAIClientOptions.Endpoint = new Uri(_baseURL);
// 创建 OpenAI 客户端并获取指定模型的聊天接口
var openaiClient = new OpenAIClient(apiKeyCredential, openAIClientOptions)
.GetChatClient(_modelID)
.AsIChatClient();
// 构建增强功能的聊天客户端(例如启用函数调用)
ChatClient = new ChatClientBuilder(openaiClient)
.UseFunctionInvocation()
.Build();
// 初始化对话历史,包含一条系统提示信息
Messages =
[
// 添加系统角色消息
new(ChatRole.System, "您是一位乐于助人的助手,帮助我们测试MCP服务器功能,优先使用中文回答!"),
];
}
}
}
2.2 处理用户的自然语言查询
在ChatAIClient文件,添加如下代码,实现与 AI 模型交互,并传入 MCP 工具。
/// <summary>
/// 异步处理用户的自然语言查询,并与 AI 模型进行交互,支持 MCP 工具调用。
/// </summary>
/// <param name="query">用户的自然语言查询内容</param>
/// <param name="tools">可用的 MCP 工具列表,用于扩展 AI 的外部能力</param>
/// <returns>AI 返回的最终文本响应结果</returns>
public async Task<string> ProcessQueryAsync(string query, IList<McpClientTool> tools)
{
// 如果消息历史为空,则初始化系统提示消息
if (Messages.Count == 0)
{
Messages =
[
new(ChatRole.System, "您是一位乐于助人的助手,帮助我们测试MCP服务器功能,优先使用中文回答!")
];
}
// 添加用户输入的消息到对话历史
Messages.Add(new(ChatRole.User, query));
// 设置请求选项,注入可用工具
var options = new ChatOptions
{
Tools = [.. tools]
};
// 调用 AI 客户端获取响应
var response = await ChatClient.GetResponseAsync(Messages, options);
// 将 AI 响应加入对话历史
Messages.AddMessages(response);
// 输出调用的工具信息
OutputToolUsageInfo(response);
// 返回模型生成的文本响应
return response.Text;
}
2.3 MCP 工具使用情况日志
在ChatAIClient文件,添加如下代码,输出 AI 调用MCP 工具的情况。
/// <summary>
/// 辅助方法:输出 AI 在响应中调用的工具信息到控制台。
/// </summary>
/// <param name="response">来自 AI 的完整响应对象</param>
private void OutputToolUsageInfo(ChatResponse response)
{
// 获取所有 Tool 角色的消息
var toolUseMessages = response.Messages.Where(m => m.Role == ChatRole.Tool).ToList();
// 判断是否调用了工具
// 获取响应中所有角色为 Tool 的消息(即 AI 调用了哪些工具)
var toolUseMessage = response.Messages.Where(m => m.Role == ChatRole.Tool);
// 判断第一条消息的内容是否多于一个(通常第一个消息是用户问题,第二个是调用函数)
if (response.Messages[0].Contents.Count > 1)
{
// 尝试从第一条消息的第二个内容项提取出函数调用信息
var functionCall = (FunctionCallContent)response.Messages[0].Contents[1];
// 设置控制台输出颜色为绿色,用于突出显示工具调用信息
Console.ForegroundColor = ConsoleColor.Green;
string arguments = "";
// 如果函数调用包含参数,则拼接参数信息
if (functionCall.Arguments != null)
{
foreach (var arg in functionCall.Arguments)
{
arguments += $"{arg.Key}:{arg.Value};";
}
// 输出调用的方法名及参数信息
Console.WriteLine($"调用方法名:{functionCall.Name};参数信息:{arguments}");
// 遍历所有 Tool 消息,输出每个工具调用的结果
foreach (var message in toolUseMessage)
{
// 提取工具调用后的执行结果
var functionResultContent = (FunctionResultContent)message.Contents[0];
Console.WriteLine($"调用工具结果:{functionResultContent.Result}");
}
// 恢复控制台默认颜色(白色)
Console.ForegroundColor = ConsoleColor.White;
}
else
{
// 如果没有参数
Console.WriteLine("工具参数为空");
}
}
else
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("本次没有调用工具");
Console.ForegroundColor = ConsoleColor.White;
}
}
}
三、为LLM添加工具能力
在前面课程基础之上,在Program.cs添加代码。

代码说明:为LLM添加工具能力,并处理客户提交的内容。
// 创建聊天客户端实例
ChatAIClient chatAIClient = new ChatAIClient();
// 进入主循环,持续接收用户输入直到输入 "exit"
while (true)
{
try
{
// 设置控制台文字颜色为黄色,提示用户输入问题
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("\n提问: ");
// 读取用户输入并去除前后空格,若为空则赋默认空字符串
string query = Console.ReadLine()?.Trim() ?? string.Empty;
// 判断用户是否输入 "exit" 以退出程序
if (query.ToLower() == "exit")
{
break;
}
// 调用异步方法处理用户查询,并传入预定义的工具列表(listToolsResult)
string response = await chatAIClient.ProcessQueryAsync(query, listToolsResult);
// 设置输出颜色为黄色,显示 AI 的响应内容
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"AI:{response}");
// 恢复控制台默认颜色(白色)
Console.ForegroundColor = ConsoleColor.White;
}
catch (Exception ex)
{
// 捕获所有异常并输出错误信息,防止程序崩溃
Console.WriteLine($"\nError: {ex.Message}");
}
}
四、测试效果
启动项目,并输入以下内容:
抓取 https://blog.csdn.net/daremeself/article/details/147166987 的内容,并markdown格式输出
调用MCP Server的工具的情况日志。

AI响应的结果:

好了,今天就分享到这边!
下一个课程:实现自己的MCP Server。
文中示例代码: https://pan.quark.cn/s/b5b8853200f9
该专栏优先在飞书发布,欢迎收藏关注!
https://www.feishu.cn/community/article?id=7507084665509904403
- End -
推荐阅读
VS Code + Cline + 魔搭MCP Server 实现抓取网页内容。
C#实现MCP Client 与 LLM 连接,抓取网页内容功能!的更多相关文章
- 5 -- Hibernate的基本用法 --4 8 外连接抓取属性
外连接抓取能限制执行SQL语句的次数来提高效率,这种外连接抓取通过在单个select语句中使用outer join来一次抓取多个数据表的数据. 外连接抓取允许在单个select语句中,通过@ManyT ...
- paip.抓取网页内容--java php python
paip.抓取网页内容--java php python.txt 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog ...
- 使用Jsoup函数包抓取网页内容
之前写过一篇用Java抓取网页内容的文章,当时是用url.openStream()函数创建一个流,然后用BufferedReader把这个inputstream读取进来.抓取的结果是一整个字符串.如果 ...
- Asp.Net 之 抓取网页内容
一.获取网页内容——html ASP.NET 中抓取网页内容是非常方便的,而其中更是解决了 ASP 中困扰我们的编码问题. 需要三个类:WebRequest.WebResponse.StreamRea ...
- ASP.NET抓取网页内容的实现方法
这篇文章主要介绍了ASP.NET抓取网页内容的实现方法,涉及使用HttpWebRequest及WebResponse抓取网页内容的技巧,需要的朋友可以参考下 一.ASP.NET 使用HttpWebRe ...
- ASP.NET抓取网页内容
原文:ASP.NET抓取网页内容 一.ASP.NET 使用HttpWebRequest抓取网页内容 这种方式抓取某些页面会失败 不过,有时候我们会发现,这个程序在抓取某些页面时,是获不到所需的内容的, ...
- c#抓取网页内容乱码的解决方案
写过爬虫的同学都知道,这是个很常见的问题了,一般处理思路是: 使用HttpWebRequest发送请求,HttpWebResponse来接收,判断HttpWebResponse中”Content-Ty ...
- C# 抓取网页内容的方法
1.抓取一般内容 需要三个类:WebRequest.WebResponse.StreamReader 所需命名空间:System.Net.System.IO 核心代码: view plaincopy ...
- ASP.NET 抓取网页内容
(转)ASP.NET 抓取网页内容 ASP.NET 抓取网页内容-文字 ASP.NET 中抓取网页内容是非常方便的,而其中更是解决了 ASP 中困扰我们的编码问题. 需要三个类:WebRequest. ...
- 爬虫学习一系列:urllib2抓取网页内容
爬虫学习一系列:urllib2抓取网页内容 所谓网页抓取,就是把URL地址中指定的网络资源从网络中读取出来,保存到本地.我们平时在浏览器中通过网址浏览网页,只不过我们看到的是解析过的页面效果,而通过程 ...
随机推荐
- 大模型本地部署搭建【ollama + deepseek + dify】
大模型本地部署搭建[在线] 一.ollama的下载.安装.配置 ollama是管理和运行所有开源大模型的平台 下载地址:https://ollama.com/download 或github下载:ht ...
- AI时代的灵魂拷问:我们真正的核心竞争力到底是什么?
"当所有人都在谈论AI+的时候,今天我想聊一点不一样的..." 上周,朋友看着我用Cursor在30分钟内完成了他过去需要两天才能完成的工作. 那一刻,一种强烈的危机感涌上心头,他 ...
- AI 核心能力与开发框架工程能力的共生关系解析
一.本质定位:能力层与载体层的互补 1. AI 能力:突破性认知的"大脑" - 定义:AI 的核心能力(如大语言模型的泛化推理.多模态感知)源于算法创新.海量数据与算力突破,其本质 ...
- @ComponentScan @MapperScan 拆分项目的时候,这两个注解很重要
今天,在做项目拆分的时候遇到了个问题,就是将service和dao层拆完之后,项目启动不起开了,如图: 最终解决办法,在启动类上增加两个注解搞定: @ComponentScan(basePackage ...
- 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
目录 什么是 Selenium 环境搭建与配置 安装 Selenium 下载浏览器驱动 基础操作 启动浏览器并访问网页 定位网页元素 通过 ID 定位 通过 CSS 选择器定位 通过 XPath 定位 ...
- Tauri新手向 - 基于LSB隐写的shellcode加载器
此篇是记录自己初次学习tauri开发工具,包含遇到的一些问题以及基本的知识,也给想上手rust tauri的师傅们一些小小的参考.此项目为保持免杀性暂不开源,希望各位师傅多多支持,反响可以的话后续会放 ...
- Golang 入门 : 变量
变量 Go语言是静态强类型语言,所以变量是有明确类型的.变量实质上就是在内存中的一小块空间,用来存储特定类型的可变数据.如果没有变量我们的程序只能将数值写死都是静态的数据,无法更改,变量可以让我们进行 ...
- 字符串成员方法:截取、替换、切割 及String成员方法小结
1.截取 subString() subString()方法有两种使用方式: 1.第一种是在括号里只放入一个索引,这时将会从放入的索引为起点,一直截取到末尾 2.第二种是在括号里放入两个索引,分别对应 ...
- 【JVM之内存与垃圾回收篇】本地方法栈
本地方法栈 Java 虚拟机栈于管理 Java 方法的调用,而本地方法栈用于管理本地方法的调用. 本地方法栈,也是线程私有的. 允许被实现成固定或者是可动态扩展的内存大小.(在内存溢出方面是相同的) ...
- SpringAI vs JBoltAI:Java企业级AI开发的框架之争与实战选型
「SpringAI vs JBoltAI:Java企业级AI开发的框架之争与实战选型」 一.Java生态的AI困局:工具碎片化与工程化缺失 1. 技术断层:从API调用到全生命周期管理多数企业仍停留在 ...