
使用 .NET 構建 STDIO 傳輸的 MCP 服務器ModelContextProtocol 2.x 實戰指南【免費下載鏈接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.項目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilotSTDIO標準輸入/輸出是 MCPModel Context Protocol服務器最簡單、最本地的傳輸方式客戶端Claude Desktop、VS Code、MCP Inspector 或自定義 CLI將服務器作為子進程啟動雙方通過 stdin/stdout 交換 JSON-RPC 幀。本文以awesome-copilot倉庫中 dotnet-mcp-builder 技能的transport-stdio參考文檔為核心結合同一技能下的包選型、工具定義與測試文檔帶你從零搭建、配置、調試一個生產可用的 .NET STDIO MCP 服務器并避開最常見的 stdout 污染陷阱。什么時候選擇 STDIO 而不是 HTTPSTDIO 適合服務器作為客戶端子進程運行的一切場景判斷標準很簡單客戶端是否負責拉起你的可執行文件、并通過管道與它對話。以下場景優先選擇 STDIO本地優先的服務器需要訪問文件系統、本地開發工具、CLI 集成單文件或 NuGet 包分發作為單個可執行文件或以dnx可運行的 NuGet 包分發追求最簡單的部署故事無需網絡、無需認證客戶端配置一條command即可需要服務器到客戶端server-to-client能力elicitation向用戶提問、通知notifications以及已廢棄的 sampling/roots——STDIO 始終完整支持這些雙向通道無需關心 HTTP 模式下的Stateless標志。如果目標是遠程、多租戶服務器需要 OAuth、網關認證、水平擴展則應改用 Streamable HTTP 傳輸詳見 transport-http.md。在技能文檔的決策樹中這兩者被明確列為新建服務器的兩個分叉新 STDIO 服務器加載transport-stdio.md新 HTTP 服務器加載transport-http.md見 SKILL.md。搭建最小 STDIO 服務器創建項目與安裝包針對官方ModelContextProtocolNuGet 包當前穩定線為2.x寫作時最新為2.2.0對齊 MCP 2026-07-28 規范STDIO 服務器需要兩個包dotnet new console -n MyStdioServer -f net10.0 cd MyStdioServer dotnet add package ModelContextProtocol --version 2.2.0 dotnet add package Microsoft.Extensions.Hosting --version 10.0.11關于包選型packages.md 給出了明確規則新 STDIO 服務器 →ModelContextProtocolMicrosoft.Extensions.HostingModelContextProtocol.AspNetCore僅用于 HTTPStreamable服務器純客戶端則用ModelContextProtocol.Core。SDK 面向.NET 8.0與netstandard2.0可在 .NET 8LTS、.NET 9、.NET 10當前 LTS新項目推薦上運行STDIO 本身對 TFM 沒有 HTTP 那樣的 ASP.NET Core 要求但仍建議新項目默認 .NET 10。需要特別警惕的是版本陷阱0.x-preview系列是預覽版API 與 2.x 存在破壞性差異1.x雖仍可編譯互操作但缺少 v2 的諸多行為HTTP 默認無狀態、discovery-first 協商、roots/sampling/logging 廢棄等。若想確認最新版本可執行dotnet search ModelContextProtocol --prerelease完整最小代碼將Program.cs替換為如下內容即可得到一個可被客戶端發現并調用工具的最小服務器// Program.cs using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using ModelContextProtocol.Server; using System.ComponentModel; var builder Host.CreateApplicationBuilder(args); // CRITICAL: stdout 是 JSON-RPC 通道所有日志必須發送到 stderr。 builder.Logging.AddConsole(o o.LogToStandardErrorThreshold LogLevel.Trace); builder.Services .AddMcpServer() .WithStdioServerTransport() .WithToolsFromAssembly(); await builder.Build().RunAsync(); [McpServerToolType] public static class EchoTool { [McpServerTool, Description(Echoes the message back to the client.)] public static string Echo(string message) $hello {message}; }這段代碼的精髓在于注冊鏈AddMcpServer()把 MCP 服務器接入 Microsoft.Extensions.Hosting 的 DI 容器WithStdioServerTransport()選擇 STDIO 傳輸WithToolsFromAssembly()掃描程序集內所有帶[McpServerToolType]標注的類并暴露其中帶[McpServerTool]的方法。技能文檔強調的精神模型正是如此.NET MCP 服務器就是一個普通的 Hosting 應用通過 DI 裝配 MCP 服務器原始類型tools/prompts/resources就是普通的 C# 方法加上特性標注見 SKILL.md。工具的 JSON Schema 由 SDK 從方法簽名與[Description]特性自動生成——這也是 tool-primitive.md 反復強調務必為每個工具和參數寫[Description]的原因這是 LLM 在挑選和構造調用時所看到的全部信息含糊的描述是工具不被使用的最主要原因。方法也可以是實例方法并依賴注入如ILoggerT、外部服務客戶端SDK 會識別非載荷參數類型并從 DI 解析。stdout/stderr 陷阱STDIO 服務器最常犯的錯誤STDIO 服務器最常見的 bug 就是有非 JSON-RPC 幀的內容寫入了 stdout。客戶端解析失敗后會直接斷開連接。任何落到 stdout 的雜訊都會讓整個協議失效。會讓 STDIO 靜默崩潰的典型來源代碼中任何位置的Console.WriteLine(...)使用默認 console sink寫入 stdout配置的日志器掛載了默認 trace listener 時的Trace.WriteLine(...)啟動時打印 banner 的第三方庫。防御性檢查清單最先配置日志重定向到 stderr上文代碼片段已演示LogToStandardErrorThreshold LogLevel.Trace確保所有等級的日志都走 stderr不要在工具方法或啟動代碼中使用Console.Write*改為將ILogger注入工具類工具類構造注入ILoggerT然后_log.LogInformation(...)第三方庫噪音通過ILogger重定向其日志或在啟動時抑制。這一點在 server-features.md 的日志章節被再次強調STDIO 服務器的 console 日志必須走 stderr否則會污染 JSON-RPC 流。同時注意MCP 通道日志loggingcapability 與客戶端的setLevel已在 2026-07-28 規范中廢棄SDK 2.x 將其標記為[Obsolete]警告MCP9005ILogger方式的日志不受影響仍是最佳默認。技能文檔的卡規則第 2 條也把它列為必須始終遵守的規則之一見 SKILL.md。服務器身份Server identity協商階段2026-07-28 規范的server/discover交換或對舊版客戶端的傳統initialize響應SDK 會自動處理兩者SDK 會發送serverInfo名稱 版本。默認從程序集元數據派生。需要覆蓋時builder.Services .AddMcpServer(options { options.ServerInfo new() { Name my-stdio-server, Version 1.0.0, Title My STDIO MCP Server // 可選的人類可讀名稱 }; }) .WithStdioServerTransport() .WithToolsFromAssembly();Title是可選的展示名Name與Version是協議中客戶端用于標識服務器的主要字段建議設置為穩定且有意義的值便于客戶端配置與日志排查。從客戶端讀取參數與環境變量客戶端如 Claude Desktop 的配置通常以參數和環境變量的形式拉起服務器。讀取方式與普通 .NET 應用完全一致string apiKey Environment.GetEnvironmentVariable(MY_API_KEY) ?? throw new InvalidOperationException(MY_API_KEY not set); string configPath args.ElementAtOrDefault(0) ?? Path.Combine(Environment.CurrentDirectory, config.json);務必在項目的 README 中記錄預期的環境變量與命令行參數讓用戶知道該在客戶端配置里填什么。這是保證配置即文檔的關鍵一步。接入 Claude Desktop在 Claude Desktop 的配置文件claude_desktop_config.json中注冊服務器{ mcpServers: { my-server: { command: dotnet, args: [run, --project, C:/path/to/MyStdioServer], env: { MY_API_KEY: ... } } } }針對不同分發形態command/args有幾種變體自包含self-contained發布將command/args替換為可執行文件路徑即可NuGet 包 dnx分發以包名和版本直接拉起無需克隆源碼command: dnx, args: [MyMcpServer, --version, 1.2.3]關于dnx分發模式packages.md 指出這是把服務器發布為 NuGet 包、讓用戶免克隆直接運行的合法分發模型它與服務器本身的構建方式正交——代碼完全一致只需更改啟動命令。接入 VS CodeGitHub Copilot Chat在項目的.vscode/mcp.json中注冊{ servers: { my-server: { type: stdio, command: dotnet, args: [run, --project, ${workspaceFolder}/src/MyMcpServer] } } }注意 VS Code 配置使用type: stdio顯式聲明傳輸類型并可用${workspaceFolder}這類占位符指代工作區路徑——這一點與 Claude Desktop 配置不同后者通過mcpServers鍵直接表達command/args/env。本地調試MCP InspectorSTDIO 服務器最干凈的調試工作流是 MCP Inspectornpx modelcontextprotocol/inspector dotnet run --project ./MyStdioServerInspector 會以子進程方式拉起你的服務器打開一個 UI讓你交互式地列出并調用工具、查看資源、觸發 elicitation、查看日志以及檢視原始 JSON-RPC 幀。若需向服務器傳遞額外參數或環境變量可在--之后追加見 testing.mdnpx modelcontextprotocol/inspector \ dotnet run --project ./MyMcpServer -- \ --some-flag valueInspector 的典型用途包括驗證工具描述是否清晰——Inspector 以 LLM 消費它們的方式渲染在真實 LLM 之外走通 elicitation 流程提交 bug 報告時捕獲精確的 JSON-RPC 載荷。除 Inspector 外testing.md 還推薦在開發/CI 中使用InMemoryTransport或更底層的StreamServerTransport/StreamClientTransport在同一進程內將真實服務器與真實客戶端對接用Pipe模擬雙向流從而在dotnet test環境中斷言客戶端視角的可觀察行為無需子進程、無需網絡、無需 Node/Docker對純邏輯則直接單測工具方法[McpServerTool]特性不影響 MCP 之外的運行時行為。優雅關閉Graceful shutdownbuilder.Build().RunAsync()已自動處理 SIGINT/SIGTERM 信號。若存在需要沖刷的后臺工作使用IHostApplicationLifetimevar host builder.Build(); var lifetime host.Services.GetRequiredServiceIHostApplicationLifetime(); lifetime.ApplicationStopping.Register(() { // flush、關閉句柄等 —— 保持快速5s避免客戶端掛起。 }); await host.RunAsync();回調里應只做輕量、快速的清理沖刷緩沖區、關閉文件/網絡句柄5 秒內完成是經驗上限客戶端在等待進程退出拖得越久越可能被客戶端判定為超時而掛起連接。與 HTTP 傳輸的對照與選型總結為了幫助你在架構決策時做出正確選擇這里給出 STDIO 與 Streamable HTTP 的快速對照HTTP 細節見 transport-http.md維度STDIOStreamable HTTP適用場景本地、單用戶、子進程啟動遠程、多租戶、可水平擴展部署復雜度無網絡、無認證command一行接入需要端點、認證OAuth/網關、反向代理配置服務器→客戶端能力elicitation/通知始終支持當前規范2026-07-28無 HTTP 會話需用多輪InputRequiredException模式包依賴ModelContextProtocolMicrosoft.Extensions.HostingModelContextProtocol.AspNetCore關鍵陷阱任何寫入 stdout 的雜訊都會破壞協議SSE 緩沖、超時、路徑前綴MapMcp不匹配導致 404常見故障速查結合技能文檔的排障清單見 SKILL.mdSTDIO 場景下遇到問題時按此順序排查工具不出現類上缺少[McpServerToolType]或沒有注冊.WithToolsFromAssembly()/.WithToolsT()連接被斷開/解析失敗幾乎可以肯定是 stdout 被污染日志 sink、Console.WriteLine、庫的 banner參數未綁定參數名必須與 JSON-RPCarguments的鍵一致復雜類型通過System.Text.Json綁定工具一直在被 LLM 誤用多半是[Description]缺失或含糊——打開 Inspector 查看 LLM 視角的 schema/描述。若涉及 sampling/elicitation/roots 這類傳統 server-to-client 調用失敗注意在 STDIO 上它們始終可用STDIO 沒有Stateless標志而當前規范的 Streamable HTTP 無狀態模式下這些遺留調用會在運行時直接拋錯——這正是本文檔開頭強調需要 server-to-client 功能時選 STDIO的原因。至此你已經掌握了從零搭建、正確配日志、注冊到兩大主流客戶端、本地調試、優雅關閉到排障的完整 STDIO MCP 服務器開發閉環可以直接基于官方ModelContextProtocol2.x 包構建自己的本地工具服務器。【免費下載鏈接】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),僅供參考