ModelContextProtocol CSharp 中提供了三种 Transport ,其核心代码在三个类中:

📅 2026/7/3 8:15:58
ModelContextProtocol CSharp 中提供了三种 Transport ,其核心代码在三个类中:
StdioClientTransportSseClientTransportStreamClientTransport下面笔者将会详细讲解 stdio、sse 两种 Transport。stdio通过本地进程间通信实现客户端以子进程形式启动 MCP Server 程序双方通过stdin/stdout交换 JSON-RPC 消息传输每条消息时以换行符分隔。本节示例项目参考 TransportStdioServer、TransportStdioClient。当使用 stdio 时McpServer 只需要实现静态方法并配置特性注解即可然后需要将该程序编译为.exe。TransportStdioServer 添加 Tool 后面讲解 Tool 这里先跳过。[McpServerToolType] public class EchoTool { [McpServerTool, Description(Echoes the message back to the client.)] public static string Echo(string message) $hello {message}; }然后创建 MCP Server 服务并使用WithStdioServerTransport()暴露接口能力。using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using TransportStdioServer; var builder Host.CreateApplicationBuilder(args); builder.Services.AddMcpServer() .WithStdioServerTransport() .WithToolsEchoTool(); builder.Logging.AddConsole(options { options.LogToStandardErrorThreshold LogLevel.Trace; }); await builder.Build().RunAsync();编译 TransportStdioServer 项目在 Windows 下会生成.exe文件复制.exe文件的绝对路径在编写 Client 时要用。C# 编写 Client 时需要通过命令行参数导入.exe文件示例如下using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol.Transport; var builder Host.CreateApplicationBuilder(args); builder.Configuration .AddEnvironmentVariables() .AddUserSecretsProgram(); var clientTransport new StdioClientTransport(new() { Name Demo Server, // 要使用绝对路径这里笔者省略了 Command E:/../../TransportStdioServer.exe }); await using var mcpClient await McpClientFactory.CreateAsync(clientTransport); var tools await mcpClient.ListToolsAsync(); foreach (var tool in tools) { Console.WriteLine($Connected to server with tools: {tool.Name}); }启动 TransportStdioClient控制台会打印 TransportStdioServer 中的所有 Mcp tool。StdioClientTransport 原理是基于命令行参数启动 TransportStdioServerStdioClient 会将命令行参数拼接起来然后以子进程方式启动 MCP Server命令行示例cmd.exe/c E:/../TransportStdioServer.exeStdioClientTransport 核心代码启动子进程SSE本节参考示例项目TransportSseServer、TransportSseClient。SSE 是通过 HTTP 长连接实现远程通信的在使用各种 AI 对话应用时AI 会像打字机一样逐个输出字符这种通过 HTTP 长连接、由 HTTP Server 服务器持续推送内容的方式就叫 sse。SSE Server 需提供两个端点/sseGET请求建立长连接接收服务器推送的事件流。/messagesPOST请求客户端发送请求至该端点。在 TransportSseServer 实现简单的 EchoTool。[McpServerToolType] public sealed class EchoTool { [McpServerTool, Description(Echoes the input back to the client.)] public static string Echo(string message) { return hello message; } }配置 MCP Server 支持 SSEusing TransportSseServer.Tools; var builder WebApplication.CreateBuilder(args); builder.Services.AddMcpServer() .WithHttpTransport() .WithToolsEchoTool() .WithToolsSampleLlmTool(); var app builder.Build(); app.MapMcp(); app.Run(http://0.0.0.0:5000);TransportSseClient 实现客户端连接 Mcp Server其代码非常简单连接到 MCP Server 后将对方支持的 Tool 列出来。using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol.Transport; var defaultOptions new McpClientOptions { ClientInfo new() { Name IntegrationTestClient, Version 1.0.0 } }; var defaultConfig new SseClientTransportOptions { Endpoint new Uri($http://localhost:5000/sse), Name Everything, }; // Create client and run tests await using var client await McpClientFactory.CreateAsync( new SseClientTransport(defaultConfig), defaultOptions, loggerFactory: NullLoggerFactory.Instance); var tools await client.ListToolsAsync(); foreach (var tool in tools) { Console.WriteLine($Connected to server with tools: {tool.Name}); }StreamableStreamable HTTP 是 SSE 的升级方案完全基于标准 HTTP 协议移除了专用 SSE 端点所有消息通过/message端点传输。本节不讲解 Streamable 。MCP Tool 说明目前社区有两大主流 LLM 开发框架分别是 Microsoft.SemanticKernel、LangChain它们都支持 Plugin 能够将本地函数、Swagger 等转换为函数将 Function 提交给 LLMAI 返回要调用的 Function 后由框架引擎实现动态调用这样功能叫 Function call。注意MCP 有很多功能其中一个叫 MCP Tool可以视为跟 Plugin 实现类似功能的东西。MCP Tool 对标 Plugin MCP 不止包含 Tool 这一功能。但是每个 LLM 框架的 Plugin 实现方式不一样其使用和实现机制跟语言特性深度绑定不能实现跨服务跨平台使用所以出现了 MCP Tool MCP Tool 是对标 Plugin 的一类功能主要目的跟 Plugin 一样提供 Function但是 MCP 有统一协议标准跟语言无关、跟平台无关但是 MCP 也不是完全替换 Plugin Plugin 依然具有很大的用武之地。MCP Tool、Plugin 最后都是转换为 Function call 的有很多人会把 MCP 、MCP Tool 和 Function call 搞混认为 MCP 是替换 Function call 的所以要注意对标 Plugin 的是 MCP Tool而两者都是转换为 Function 给 AI 使用的。MCP Tool以 TransportSseClient 为例如果要在 Client 调用 TransportSseServer 的 Tool需要指定 Tool 名字和参数。后续将会讲解如何通过 SK 将 mcp tool 提供给 AI 模型。var echoTool tools.First(x x.Name Echo); var result await client.CallToolAsync(Echo, new Dictionarystring, object? { { message,痴者工良} }); foreach (var item in result.Content) { Console.WriteLine($type: {item.Type},text: {item.Text}); }让我们再回顾 MCP Server 是怎么提供 Tool 的。首先服务端需要定义 Tool 类和函数。[McpServerToolType] public sealed class EchoTool { [McpServerTool, Description(Echoes the input back to the client.)] public static string Echo(string message) { return hello message; } }Mcp server 可以通过以下两种方式暴露 tool。// 直接指定 Tool 类 builder.Services .AddMcpServer() .WithHttpTransport() .WithToolsEchoTool() .WithToolsSampleLlmTool(); // 扫描程序集 builder.Services .AddMcpServer() .WithHttpTransport() .WithStdioServerTransport() .WithToolsFromAssembly();Client 识别服务端的 Tool 列表时可以使用McpClientTool.ProtocolTool.InputSchema获取 tool 的输入参数格式其内容格式示例如下Annotations: null Description: Echoes the input back to the client. Name: Echo InputSchema: {title:Echo,description:Echoes the input back to the client.,type:object,properties:{message:{type:string}},required:[message]}[McpServerToolType]用于将包含应该作为ModelContextProtocol.Server.McpServerTools公开的方法的类型属性化。[McpServerTool]用于指示应该将方法视为 ModelContextProtocol.Server.McpServerTool。[Description]则用于添加注释。依赖注入在实现 Tool 函数时服务端是可以通过函数实现依赖注入的。参考示例项目 InjectServer、InjectClient。添加一个服务类并注册到容器中。public class MyService { public string Echo(string message) { return hello message; } }builder.Services.AddScopedMyService();在 Tool 函数中注入该服务[McpServerToolType] public sealed class MyTool { [McpServerTool, Description(Echoes the input back to the client.)] public static string Echo(MyService myService, string message) { return myService.Echo(message); } }将 MCP Tool 提交到 AI 对话中前面提到MCP Tool 和 Plugin 都是实现 Function call 的一种方式当在 AI 对话中使用 Tool 时其主要过程如下当你提出问题时client 将你的问题发送给 LLM LLM 分析可用的 tools 并决定使用哪些 toolclient 通过 MCP server 执行选择的 tool结果被发回给 LLMLLM 制定自然语言响应响应显示给你这个过程并不是只有一两次可能发生多次具体细节将会在高德地图 MCP 实战中讲解这里只是简单提及。将 Tool 提交到对话上下文的伪代码// Get available functions. IListMcpClientTool tools await client.ListToolsAsync(); // Call the chat client using the tools. IChatClient chatClient ...; var response await chatClient.GetResponseAsync( your prompt here, new() { Tools [.. tools] },高德地图 MCP 实战聊了这么久终于到了实战对接环节本节将会通过高德地图案例讲解 MCP Tool 的逻辑细节和对接使用方式。代码参考示例项目 amap。高德地图 MCP Server 目前主要提供的功能地理编码逆地理编码IP 定位天气查询骑行路径规划步行路径规划驾车路径规划公交路径规划距离测量关键词搜索周边搜索详情搜索其 Tool 名称如下maps_direction_bicycling maps_direction_driving maps_direction_transit_integrated maps_direction_walking maps_distance maps_geo maps_regeocode maps_ip_location maps_around_search maps_search_detail maps_text_search maps_weather高德地图每天都给开发者提供了免费额度所以做该实验时不需要担心需要付费。打开 我的应用 | 高德控制台 创建一个新的应用然后复制应用 key。高德 mcp 服务器地址https://mcp.amap.com/sse?key{在高德官网上申请的key}在 amap 项目的appsettings.json添加以下 json替换里面的部分参数。笔者注除了 gpt-4o 模型其它注册 Function call 的模型也可以使用。McpServers: { amap-amap-sse: { url: https://mcp.amap.com/sse?key{在高德官网上申请的key} } }, AIModel: { ModelId: gpt-4o, DeploymentName: gpt-4o, Endpoint: https://openai.com/, Key: aaaaaaaa }导入配置并创建日志var configuration new ConfigurationBuilder() .AddJsonFile(appsettings.json) .AddJsonFile(appsettings.Development.json) .Build(); using ILoggerFactory factory LoggerFactory.Create(builder builder.AddConsole());第一步创建 mcp 客户端连接高德 MCP Server并获取 Tool 列表。var defaultOptions new McpClientOptions { ClientInfo new() { Name 地图规划, Version 1.0.0 } }; var defaultConfig new SseClientTransportOptions { Endpoint new Uri(configuration[McpServers:amap-amap-sse:url]!), Name amap-amap-sse, }; await using var client await McpClientFactory.CreateAsync( new SseClientTransport(defaultConfig), defaultOptions, loggerFactory: factory); var tools await client.ListToolsAsync(); foreach (var tool in tools) { Console.WriteLine($Connected to server with tools: {tool.Name}); }第二步连接 AI 模型和配置 MCP