
用 C# 构建生产级 MCP Serverawesome-copilot 中 C# MCP Server Expert 的完整实践指南【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilotawesome-copilot 是一个社区贡献的 GitHub Copilot 指令、Agent 与技能集合仓库。其中的csharp-mcp-expert.agent.md定义了一个专注于使用 C# SDK 构建 Model Context ProtocolMCP服务器的专家型 Agent它以ModelContextProtocol系列 NuGet 包为核心覆盖 .NET 依赖注入、异步编程、协议级错误处理、工具/提示词/资源三类原语的设计以及 stdio 传输与协议错误的调试。本文以该 Agent 定义为主干结合仓库内 同主题指令文档 与 dotnet-mcp-builder 技能库 的源码级细节完整还原一套可直接落地的 C# MCP Server 开发方法论——读完你既能按规范搭出第一个可运行的 MCP 服务器也能掌握工具Tool、提示词Prompt、资源Resource三大原语的生产级写法与常见排障手段。一、先理解这篇 Agent 的定位与它面向的技术栈在 awesome-copilot 的 agents 目录 中csharp-mcp-expert.agent.md是一份“角色即能力清单”的系统提示词文件front matter 声明了它的名称C# MCP Server Expert与模型建议GPT-4.1正文把一个“世界级 C# MCP 服务器专家”应掌握的知识拆成了四块核心包掌握ModelContextProtocol、ModelContextProtocol.AspNetCore、ModelContextProtocol.Core三个 NuGet 包.NET 架构功底Microsoft.Extensions.Hosting、依赖注入、服务生命周期管理MCP 协议理解客户端-服务器通信、tool/prompt/resource 三类模式工程素养async/await、CancellationToken、安全、错误处理、日志、测试、可维护性。这与仓库内配套的 csharp-mcp-server.instructions.md 互相印证前者负责“专家怎么写代码”后者以.cs/.csproj为作用域定义硬性规则applyTo: **/*.cs, **/*.csproj。两者的共同结论是一个 .NET MCP Server本质上是一个普通的Microsoft.Extensions.Hosting或 ASP.NET Core WebApplication应用通过依赖注入把 MCP 服务器接进去而已。二、包选型三个 NuGet 包分别什么时候用Agent 与指令文档都强调先选对包。仓库技能库 packages.md 对三者做了精确分工包适用场景附带能力ModelContextProtocol大多数项目与 STDIO 服务器的默认选择引入Core与Microsoft.Extensions.Hosting集成提供AddMcpServer、WithToolsFromAssembly等属性发现机制ModelContextProtocol.AspNetCore托管在 ASP.NET Core 中的 HTTPStreamable服务器上述全部 WithHttpTransport与MapMcpModelContextProtocol.Core纯客户端、自定义宿主、低层场景不想引入Microsoft.Extensions.*仅协议 传输 低层McpServer.Create/McpClient.CreateAsync针对“当前应该用哪个版本”仓库内存在两条并列的证据链使用时需要按场景选择Agent 文档与配套指令写于 SDK 预发布时代明确要求始终带--prerelease标志安装dotnet add package ModelContextProtocol --prerelease而面向最新 2.x 稳定版的 dotnet-mcp-builder 技能 则给出固定稳定版本写作时为 2.x 线的工程实践并警告0.x预览版存在破坏性差异、1.x虽可编译但早于 2026-07-28 规范修订。新建项目时可用dotnet search ModelContextProtocol --prerelease查看最新可用版本。技能库给出的三条脚手架命令是最佳起点# STDIO 服务器 dotnet new console -n MyMcpServer -f net10.0 dotnet add package ModelContextProtocol dotnet add package Microsoft.Extensions.Hosting # HTTPStreamable服务器 —— dotnet new web 正好是 MapMcp 需要的宿主 dotnet new web -n MyMcpServer -f net10.0 dotnet add package ModelContextProtocol.AspNetCore # 纯客户端 dotnet new console -n MyMcpClient -f net10.0 dotnet add package ModelContextProtocol.CoreSDK 的目标框架是.NET 8.0与netstandard2.0因此可运行在 .NET 8 LTS、.NET 9、.NET 10 LTS 上若写 HTTP 服务器则需要支持 ASP.NET Core 的 TFM即 .NET 8/9/10。三、服务器骨架DI 优先 stderr 日志 传输注册Agent 的“Your Approach”反复强调Dependency Injection First。指令文档给出一份可整体复制的基准服务器见 csharp-mcp-server.instructions.md 的 Common Patternsvar builder Host.CreateApplicationBuilder(args); builder.Logging.AddConsole(options options.LogToStandardErrorThreshold LogLevel.Trace); builder.Services .AddMcpServer() .WithStdioServerTransport() .WithToolsFromAssembly(); await builder.Build().RunAsync();这段代码包含四条黄金法则Agent 文档逐条列明用Host.CreateApplicationBuilder获得完整的 DI 容器与生命周期管理而不是手写裸McpServer日志一律写 stderrLogToStandardErrorThreshold LogLevel.Trace。原因是 STDIO 传输下stdout 是 JSON-RPC 通信信道任何Console.WriteLine、默认控制台日志输出或第三方库启动横幅都会污染协议流直接导致客户端解析失败断开连接。这是仓库内 transport-stdio.md 标注的“STDIO 头号坑”Agent 也把“诊断 stdio 传输问题”列为核心专长之一用.WithToolsFromAssembly()自动发现当前程序集中所有标注[McpServerToolType]的类原语即方法工具、提示词、资源都是普通 C# 方法SDK 依据方法签名与[Description]自动生成 JSON Schema参数从 JSON-RPC 绑定。技能库中“30 秒心智模型”补充了一个可选维度提示词与资源也可以按需显式注册WithPromptsMyPrompts()/WithResourcesMyResources()。需要给服务器自定义身份时可在AddMcpServer(options ...)中设置ServerInfoName/Version/Title。四、三类原语的专家级规范Agent 文档把最佳实践拆成 Tools、Prompts、Resources 三组每组都有明确的属性与返回类型约束。以下逐类展开并与仓库技能库的实现细节对齐。4.1 Tools函数即工具名字用 snake_case核心规则Agent 原文 指令文档类上标[McpServerToolType]方法上只有[McpServerTool]是不会被WithToolsFromAssembly发现的方法上标[McpServerTool(Name tool_name)]命名遵循 snake_case技能库补充说明工具显示名默认就是方法名PascalCase 不会自动转 snake_case需要明确改名时使用Name属性把相关工具按类分组Agent 举例如ComponentListTools、ComponentDetailTools即列表类与详情类各一组返回简单类型string或可 JSON 序列化的对象技能库进一步列出返回类型与“LLM 看到什么”的对应表string/int/bool等 → 单文本内容块DTOrecord/class→ 文本块中的 JSON 面向新客户端的structuredContentIEnumerableDTO→ JSON 数组ContentBlock系列ImageContentBlock/AudioContentBlock/EmbeddedResourceBlock→ 原样透传的内容块CallToolResult→ 完全掌控Content/StructuredContent/IsError所有工具与参数都加[Description]来自System.ComponentModel这是 LLM 决定“何时调用、如何传参”的唯一依据描述含糊是工具不被使用的第一大原因输出格式化为 Markdown并在结果里附带使用提示Agent 原话示例“Use GetComponentDetails(componentName) for more information”引导 LLM 进入下一步调用。一个可复制的“标准工具”形状指令文档原例[McpServerToolType] public static class MyTools { [McpServerTool, Description(Description of what the tool does)] public static string ToolName( [Description(Parameter description)] string param) $Result: {param}; }async、CancellationToken 与依赖注入指令文档原例工具方法可以是同步或异步的SDK 会识别并“特判”下列参数类型——它们不会进入工具 Schema而是从环境注入[McpServerTool, Description(Fetches data from a URL)] public static async Taskstring FetchData( HttpClient httpClient, // 从 DI 注入的服务 [Description(The URL to fetch)] string url, // 真正的 JSON-RPC 参数 CancellationToken cancellationToken) // 由 SDK 从请求传播 await httpClient.GetStringAsync(url, cancellationToken);技能库 tool-primitive.md 补充了完整的“被特判参数”清单IMcpServer/McpServer、CancellationToken、RequestContextCallToolRequestParams、IServiceProvider以及任何 DI 可解析且不被识别为原始负载的服务。其余参数一律作为 JSON-RPC 参数进入 Schema。4.2 Prompts一个提示词类一个提示词返回 ChatMessageAgent 对 Prompts 的约束与 Tools 明显不同——提示词是给“用户”而不是给 LLM 从菜单挑选触发的相当于聊天客户端里的“斜杠命令”。核心规则类上标[McpServerPromptType]方法标[McpServerPrompt(Name prompt_name)]snake_case每个提示词单独一个类便于组织与维护方法返回ChatMessage而非string以符合 MCP 协议代表用户指令的提示用ChatRole.User。技能库的对应表给出四个层级ChatMessage单条、IEnumerableChatMessage多轮会话种子、PromptMessage/IEnumerablePromptMessage需要细粒度控制内容块时、GetPromptResult完全掌控Messages与Description提示词内容中应包含充足上下文组件细节、示例、准则Agent 建议用StringBuilder拼装复杂多段提示用[Description]说清“该提示生成什么、何时使用”可选参数带默认值实现灵活的提示定制。一个同时覆盖“多消息 结构化”的示例技能库 prompt-primitive.md 原例[McpServerPromptType] public class CodePrompts { [McpServerPrompt, Description(Generates a code review prompt.)] public static IEnumerableChatMessage CodeReview( [Description(The programming language)] string language, [Description(The code to review)] string code) [ new(ChatRole.User, $Please review the following {language} code:\n\n{language}\n{code}\n), new(ChatRole.Assistant, Ill review the code for correctness, style, and potential improvements.) ]; }注册时别忘了显式接线——新增了[McpServerPromptType]类却漏掉.WithPrompts...()或.WithPromptsFromAssembly()是技能库“金科玉律”第 7 条点名的常见遗漏会让提示词“隐形”。4.3 Resources用 UriTemplate 暴露静态与动态内容Resources 是通过 URI 寻址、由服务器暴露的“事物”宿主列出后由用户挑选附加到对话。Agent 给出的[McpServerResource]四个关键属性要逐一对齐到实现上UriTemplate带可选参数的 URI 模式如myapp://component/{name}Name资源唯一标识Title人类可读标题MimeType内容类型通常text/markdown或application/json。两种形态resource-primitive.md静态资源用固定 URI适合单例配置如projectname://guides动态资源模板用带占位符的 URI如projectname://component/{name}占位符按名字映射到方法参数。[McpServerResourceType] public class DocumentResources { [McpServerResource( UriTemplate docs://articles/{id}, Name Article, MimeType text/markdown)] [Description(Returns an article by its ID.)] public static ResourceContents GetArticle(string id) { string? content LoadArticle(id); if (content is null) throw new McpException($Article not found: {id}); return new TextResourceContents { Uri $docs://articles/{id}, MimeType text/markdown, Text content }; } }返回类型与工具同样有规则string会被包装为TextResourceContentsbyte[]包装为BlobResourceContents也可以直接返回TextResourceContents/BlobResourceContents二进制用BlobResourceContents.FromBytes(...)或多段IEnumerableResourceContents。把相关资源分组到同一类Agent 例GuideResources、ComponentResources文档类资源返回格式化 Markdown并包含指向相关资源的导航提示与链接。资源不存在时优雅地报错如上面的McpException而不是返回空串。安全要点若资源直接暴露文件系统绝不能信任 URI 原样拼接路径——必须先做路径规整再校验前缀防止路径穿越技能库中的file://workspace/{*relativePath}示例在组合路径后执行Path.GetFullPathStartsWith(root)双重防护。4.4 三类原语的选择边界仓库技能库给出一组极易混淆的判定准则Tool由 LLM 主动调用以“做某事”取数或改状态适合get_weather、create_issuePrompt由用户从菜单触发并自行提供参数输出是消息而非数据适合/summarize、/code-review、/draft-emailResource为对话附加只读、可寻址、可枚举的上下文文档、配置、Schema宿主决定何时加载如果既想被搜索又想被引用就同时暴露两者search_articles工具负责返回 URI 列表docs://articles/{id}资源模板负责按 URI 取内容。五、错误处理与协议级异常Agent 文档对错误处理有非常具体的协议要求指令文档将其落成两个规则参数校验失败抛McpProtocolExceptionMcpErrorCode.InvalidParams工具内部业务失败抛普通异常即可SDK 会捕获并返回IsError true的CallToolResult消息进入文本块——LLM 能读到并据此纠正后重试。技能库 tool-primitive.md 给出了这两条规则的判定启发式如果 LLM 应该换参数重试抛普通异常如果调用本身在协议层就是畸形的LLM 无法修复才抛McpProtocolException。[McpServerTool, Description(…)] public static string Process(string input) { if (string.IsNullOrWhiteSpace(input)) throw new McpProtocolException(Missing required input, McpErrorCode.InvalidParams); return $Processed: {input}; }一个隐蔽的反模式也被技能库单独点出把失败当作字符串failed返回会被 SDK 当作一次成功调用。隐藏错误必须走“抛异常”或显式构造CallToolResult { IsError true }两条路。六、需要“反打回客户端”的场景Sampling 与高级模式工具若需要调用客户端的 LLM而非自己内置模型Agent 与指令文档给出的标准做法是McpServer.AsSamplingChatClient()——把服务器自身转成一个采样聊天客户端向远端发起请求[McpServerTool, Description(Analyzes content using the clients LLM)] public static async Taskstring Analyze( McpServer server, [Description(Content to analyze)] string content, CancellationToken cancellationToken) { var messages new ChatMessage[] { new(ChatRole.User, $Analyze this: {content}) }; return await server.AsSamplingChatClient() .GetResponseAsync(messages, cancellationToken: cancellationToken); }需要注意版本语境面向 2026-07-28 规范修订的 dotnet-mcp-builder 技能 明确指出 sampling、roots 与 MCP 信道日志已被规范弃用SDK 2.x 将其标为[Obsolete]编译警告MCP9005新设计应优先使用多轮往返的InputRequiredExceptioninput_required模式与ILogger日志仅在与低版本客户端互通时按文档化过渡手段抑制该警告。这也是“专家 Agent 配置”与“持续演进的新版技能库”共存于 awesome-copilot 的价值Agent 给出心智框架技能库给出针对最新规范版本的勘误。七、生产化增强过滤中间件、进度通知与服务指令在工具/提示词/资源之外server-features.md 展示了 Agent 所称“Best Practices安全、错误处理、日志、测试、可维护性”在实现层的落地手段调用过滤器Filters类似 ASP.NET Core 中间件用.WithCallToolFilter(async (ctx, next) ...)包裹工具调用统一做鉴权、遥测、限流与审计——例如用Stopwatch记录每个工具的耗时日志进度通知长耗时工具中按RequestContextCallToolRequestParams里的Meta.ProgressToken判定客户端是否在监听是则通过SendNotificationAsync发送ProgressNotification更新进度条服务指令在AddMcpServer(options ...)中设置ServerInstructions作为初始化时下发给宿主、可能被拼进系统提示的说明技能库提醒它“每个 token 都由用户买单”务必精简能力宣告裁剪通过options.Capabilities中的Tools/Prompts/Resources显式决定宣告哪些能力默认全部宣告已注册项。八、调试与测试Agent 的“Common Scenarios”在仓库中的答案Agent 文档把“诊断 stdio 传输问题、序列化问题、协议错误”列为强项。仓库技能库 testing.md 给出了与该心智完全对应的三条排障路径1. MCP Inspector 交互调试启动服务器并连接后可逐一手动调用工具、查看资源、检查原始 JSON-RPC 帧特别适合在没有真实 LLM时验证工具描述是否清晰。2. 进程内集成测试推荐用PipeStreamServerTransport/StreamClientTransport把真实的服务器和真实的客户端在同一进程内接起来直接对“客户端可见的暴露行为”做断言——不依赖子进程与网络任何能跑dotnet test的环境CI 同样适用都能执行[Fact] public async Task GetWeather_returns_text() { var clientToServer new Pipe(); var serverToClient new Pipe(); await using var server McpServer.Create( new StreamServerTransport( clientToServer.Reader.AsStream(), serverToClient.Writer.AsStream()), new McpServerOptions { ToolCollection [McpServerTool.Create( (string city) ${city}: 18°C, new() { Name GetWeather })] }); var serverTask server.RunAsync(); await using var client await McpClient.CreateAsync( new StreamClientTransport( clientToServer.Writer.AsStream(), serverToClient.Reader.AsStream())); var tools await client.ListToolsAsync(); var tool tools.Single(t t.Name GetWeather); var result await tool.CallAsync(new Dictionarystring, object? { [city] Brussels }); Assert.False(result.IsError); Assert.Equal(Brussels: 18°C, result.Content.OfTypeTextContentBlock().Single().Text); }3. 纯逻辑单测[McpServerTool]在 MCP 装配之外不改变方法行为——工具方法只是普通方法可直接单测无需任何 MCP 设施。高频问题对照表技能库 指令文档共同覆盖 Agent 所说的“stdio 传输问题 / 序列化错误 / 协议错误”三类故障症状根因与对策STDIO 服务器无响应/连接被断开有东西写入了 stdoutConsole.WriteLine、默认日志 sink、库启动横幅把所有日志切到 stderr工具不出现在客户端类上缺[McpServerToolType]或漏了.WithToolsFromAssembly()/.WithToolsT()注册参数绑定失败方法参数名必须与 JSON-RPCarguments的键一致复杂类型走System.Text.Json绑定HTTP 根路径 404app.MapMcp()挂在根app.MapMcp(/mcp)则路径是http://host/mcpLLM 总是误用工具用 Inspector 看 LLM 视角的 Schema 与描述——多数情况是[Description]写得太含糊升级 2.x 后出现MCP9005警告代码用了已被弃用的 sampling/roots/logging API规划迁移而非永久压制九、输出风格与协作预期Agent 赋予你的“交付标准”Agent 文档的 “Response Style” 定义了 MCP 服务器领域里“高质量交付”的检查清单既是读者判断该 Agent 输出质量的标尺也可反过来当作你自己编码时的验收标准给出可直接复制运行的完整代码示例含必要的using与命名空间声明对复杂或不直观的逻辑加内联注释解释“为什么这样设计”主动指出潜在陷阱与常见错误例如 stdout 污染、漏注册、参数命名不一致相关时提供改进建议与替代方案、常见问题的排障提示、规范的缩进与留白安全始终在场凡是访问文件、网络或系统资源的工具都要先想安全影响用对 LLM 友好的描述把“何时用、怎么用、返回什么”讲清楚。十、总结在 awesome-copilot 中快速上手 C# MCP Server围绕agents/csharp-mcp-expert.agent.md这条专家 Agentawesome-copilot 还配套了可直接引用的三份关联资产建议按序使用csharp-mcp-expert.agent.md角色与最佳实践总纲适合在编码前建立心智模型csharp-mcp-server.instructions.md针对.cs/.csproj的规则清单含基础服务器、简单工具、DI 工具、Sampling 四个可直接复制的 Common Patternsdotnet-mcp-builder 技能库 及其 references 分册面向最新规范/版本的勘误与逐项参考传输、工具、提示词、资源、测试等。把这套资产配合使用你既能得到 Agent 文档所倡导的“DI 优先、属性驱动、[Description]全覆盖、stderr 日志、McpProtocolException协议错误”的开发范式也能用技能库中的最新版本约束与测试脚手架把服务器打磨到可交付状态——这正是该仓库“instructions、agents、skills 一体”设计意图的直接体现。【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考