MCP 协议中提供了一种机制 ,通过在 MCP client 中设置,可以为 MCP 服务端提供调用 LLM
的桥梁。 在 .net
中的处理流程就是 MCP Client
中配置回调机制,然后在 MCP Server 工具类
中注入 McpServer
对象,然后调用 var chatClient = thisServer.AsSamplingChatClient();
得到 IChatClient
。 于是就可以与普通的调用 LLM
流程一样的处理了
配置 MCP Client
中处理回调
创建 mcpClient 并配置回调函数
# 生成 mcpClient 时配置 mcpClientOptions 指定 llm 回调函数, 这里调用下面的 UpdateOptions 函数进行配置
var mcpClientOptions = new McpClientOptions();
updateOptions?.Invoke(mcpClientOptions);
var mcpClient = await McpClient.CreateAsync(new StdioClientTransport(stdioClientTransportOptions), mcpClientOptions);
mcpClient 中配置 llm 回调函数
// 1. 更新 MCP 采样回调 (配置 mcp client 的 llm 回调函数处理)
private void UpdateOptions(McpClientOptions options, AsyncServiceScope serviceScope)
{
options.Handlers = new McpClientHandlers
{
// 指定 SamplingHandler 即为回调函数
// requestParams 为 MCP Server 传入的查询参数
SamplingHandler = async (requestParams, progress, cancellationToken) => // 接收服务端发送的调用请求
{
if (requestParams == null)
{
throw new InvalidOperationException("没有输入有效的查询参数");
}
// 配置 LLM 的调用参数
var chatOptions = new ChatOptions
{
MaxOutputTokens = requestParams.MaxTokens,
Temperature = requestParams.Temperature,
};
// LLM 对话数据
var messages = (
from samplingMessage in requestParams.Messages
let content = (samplingMessage.Content as TextContentBlock)?.Text ?? string.Empty
where !string.IsNullOrWhiteSpace(content)
select new ChatMessage(this.GetChatRole(samplingMessage.Role), content)
)
.ToList();
// 调用 llm
var chateClient = serviceScope.ServiceProvider.GetRequiredService<IChatClient>();
var response = await chateClient.GetResponseAsync(messages, chatOptions, cancellationToken);
// 返回结果
return new CreateMessageResult
{
Content = new TextContentBlock { Type = "text", Text = response.Text, },
Model = response.ModelId ?? string.Empty,
Role = response.Messages.LastOrDefault()?.Role == ChatRole.Assistant ? Role.Assistant : Role.User,
};
},
};
}
MCP Client
调用 MCP Server
// 创建 mcpClient 作为 tools 传入 chateClient 供 llm 调用
// 询问 llm 穿衣指数,AI 会调用 MCP Server 中的 GetDressingAdvice 函数
// 而 MCP Server 中的 GetDressingAdvice 函数中会回调用访问 llm
[Fact(DisplayName = "测试 MCP 采样回调")]
public async Task TestSamplingAsync()
{
await using var serviceProvider = this.CreateServiceProviderCore(it => it.UseBaiLianAiChatClinet());
await using var serviceScope = serviceProvider.CreateAsyncScope();
// 创建可用的工具列表, 并在其中调用 UpdateOptions 配置 SamplingHandler 作为 LLM 回调处理函数
var mcpClient = await this.CreateMcpClient(options => this.UpdateOptions(options, serviceScope));
var tools = await mcpClient.ListToolsAsync();
// 进行聊天,传入天气工具, 记得设置一下 UseFunctionInvocation
using var chateClient = serviceProvider.GetRequiredService<IChatClient>().ConfigChatClient(it => it.UseFunctionInvocation());
var chatResponse = await chateClient.GetResponseAsync(new ChatMessage(ChatRole.User, "根据天气推荐在南京如何穿衣"), new ChatOptions { Tools = [.. tools,], });
// 输出 AI 查询的结果
this.LogInfo(chatResponse.Text);
}
MCP Server
中注入 McpServer
并调用
// 1. 注入 McpServer
// 2. 调用 thisServer.AsSamplingChatClient() 获得 IChatClient
// 3. 通过 `IChatClient` 调用 `LLM`
[McpServerTool]
[Description("返回指定城市的当前的穿衣建议")]
public async Task<string> GetDressingAdvice(
McpServer thisServer,
[Description("待查询穿衣建议的城市的 CityId")] string cityId)
{
// 查询出天气信息
var weather = await this.GetCityWeatherAsync(cityId);
// 获取 ichatclient
var chatClient = thisServer.AsSamplingChatClient();
// 调用 llm 分析穿衣指数
const string message = @"""
你是一个专业的天气与生活助手。请根据用户提供的【城市名称】、【天气状况】(如晴、多云、小雨、大雨、雪等)和【当前气温(℃)】,生成一条简洁、实用、人性化的穿衣建议。
要求:
1. 先简要说明今日体感(如“微凉”“炎热”“湿冷”等);
2. 给出具体的穿衣推荐(如“建议穿长袖衬衫+薄外套”);
3. 如遇雨、雪或高温晴天,请附加相应提示(如“记得带伞”“注意防晒”);
4. 语言亲切自然,避免专业术语,适合普通大众阅读;
5. 输出控制在 2–3 句话内,不超过 80 字。
输入格式示例:
- 城市:上海
- 天气:小雨
- 气温:19℃
请按上述要求生成穿衣建议。
""";
var messages = new List<ChatMessage>
{
new(ChatRole.System, message),
new(ChatRole.User, weather),
};
using var ts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
var response = await chatClient.GetResponseAsync(messages, cancellationToken: ts.Token);
// 返回结果
return response.Text;
}