1. 三个 .NET MCP 库到底怎么选:从“AI助手工具链”说起
如果你正在用 .NET 写 AI 助手,大概率会遇到一个绕不开的问题:模型怎么安全、稳定地调用你本地的函数、查数据库、读文件?MCP(Model Context Protocol)就是干这个的。它把“模型能调用的工具”标准化成一套协议,客户端(比如 Claude Code、Cline、Codex 这类编码助手)通过 stdio 或 HTTP 跟你的 MCP Server 通信,Server 再把请求转成你写的 C# 方法。
.NET 生态里目前能拿来做 MCP Server 的库,讨论度最高的就是三个:MCPSharp、mcpdotnet、ModelContextProtocol.NET。名字很像,定位差别却不小。MCPSharp 主打属性化 API,一个[McpTool]标记就能把方法暴露出去,适合快速把现有业务方法变成工具;mcpdotnet 走的是 Host + DI 的路线,日志和异步处理做得扎实,适合放进生产级服务;ModelContextProtocol.NET 则更像一个还在施工的框架,接口预留得多,但文档和功能完整度还差一截。
这篇文章不堆概念,直接给你三者的可复制配置片段、本地验证步骤,以及它们分别怎么对接 TaoToken 的统一 Key/API 通道。TaoToken 在这里的角色是“统一入口”:你不需要为每个模型单独申请 Key、改 Base URL,只要把 MCP Server 里要调用的模型请求指向 TaoToken 的 API 地址,用同一个 Key 就能切换不同模型。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api 。
先说结论,方便你对号入座:想半天内跑通一个能用的 MCP Server,选 MCPSharp;要长期维护、需要详细日志和并发控制,选 mcpdotnet;想研究协议扩展、做 AOT 或 WebSocket 实验,可以看 ModelContextProtocol.NET,但别把它当生产首选。下面逐个拆。
2. TaoToken 前置:统一 Key 与 API 通道怎么准备
在写任何 MCP Server 之前,先把“模型调用通道”这件事解决掉。很多人的 MCP Server 里会内嵌一个对模型的请求(比如让模型决定调用哪个工具、或者做二次总结),如果每个模型都单独配 Key,代码里会散落一堆环境变量。TaoToken 的做法是给你一个统一的 API 入口和一把 Key,模型 ID 在请求体里指定。
你需要准备三样东西,我把它叫“三件套”:
- Base URL:
https://taotoken.net/api - API Key:在控制台创建,形如
sk-... - Model ID:比如
claude-sonnet-4-20250514、gpt-4o这类,按你实际要用的填
创建 Key 的入口在控制台的 API Keys 页面:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。如果你还没决定用哪个模型,可以先去模型对话页面试一下:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。
拿到 Key 之后,建议用环境变量管理,别硬编码进代码:
# Linux / macOS export TAOTOKEN_API_KEY="sk-你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api" # Windows PowerShell $env:TAOTOKEN_API_KEY="sk-你的Key" $env:TAOTOKEN_BASE_URL="https://taotoken.net/api"这里有个容易踩的坑:Base URL 末尾不要带/v1或/chat/completions,SDK 一般会自己拼路径。如果你用的是 OpenAI 兼容的 SDK,通常只需要把base_url设成https://taotoken.net/api,然后api_key填 TaoToken 的 Key。实测下来,这样配置后切换模型只需要改model字段,其他代码不用动。
对于 MCP Server 来说,TaoToken 的接入点通常有两个位置:一是 Server 内部调用模型做意图识别或参数补全;二是客户端(编码助手)本身通过 TaoToken 访问模型。前者你在 C# 代码里用 HttpClient 或 OpenAI SDK 调;后者在客户端的配置里填。本文重点讲前者,因为三个 MCP 库的差异主要体现在 Server 端。
如果你打算长期做编码类 Agent,可以了解下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,遇到协议细节可以先翻这里。
3. 可复制配置:三个库的 Server 端写法与 TaoToken 对接
这一节是核心,每个库我都给你一段能直接跑的配置/代码,并且说明 TaoToken 的三件套填在哪里。注意,三个库的包名和命名空间不同,别混用。
3.1 MCPSharp:属性化 API 最快上手
MCPSharp 的风格是“标记即工具”。你写一个普通类,方法上加[McpFunction],参数上加[McpParameter],然后启动 Server 就行。它适合把已有的业务方法快速暴露给 AI 助手。
先装包:
dotnet add package MCPSharp然后写工具类。下面这个例子除了加法,还加了一个“调用 TaoToken 做文本总结”的工具,展示怎么在 MCP 工具内部走统一 Key:
using MCPSharp; using System.Net.Http.Headers; using System.Text; using System.Text.Json; [McpTool("AssistantTools", "AI 助手常用工具集")] public class AssistantTools { private static readonly HttpClient _http = new HttpClient(); [McpFunction("Add", "两个整数相加")] public static int Add( [McpParameter(true, "第一个数")] int a, [McpParameter(true, "第二个数")] int b) { return a + b; } [McpFunction("Summarize", "调用 TaoToken 统一通道总结文本")] public static async Task<string> Summarize( [McpParameter(true, "待总结文本")] string text) { var apiKey = Environment.GetEnvironmentVariable("TAOTOKEN_API_KEY"); var baseUrl = Environment.GetEnvironmentVariable("TAOTOKEN_BASE_URL") ?? "https://taotoken.net/api"; var payload = new { model = "claude-sonnet-4-20250514", messages = new[] { new { role = "user", content = $"请用一句话总结:{text}" } } }; var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/v1/chat/completions"); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); req.Content = new StringContent( JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); var resp = await _http.SendAsync(req); resp.EnsureSuccessStatusCode(); var json = await resp.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(json); return doc.RootElement .GetProperty("choices")[0] .GetProperty("message") .GetProperty("content") .GetString() ?? ""; } } // Program.cs await MCPServer.StartAsync("AssistantServer", "1.0.0");注意Summarize里 Base URL 用的是https://taotoken.net/api,路径拼/v1/chat/completions。如果你的 SDK 已经带了/v1,就不要再重复。Model ID 按你实际用的填,切换模型只改这一行。
3.2 mcpdotnet:Host + DI,日志和异步更稳
mcpdotnet 的写法更接近 ASP.NET Core 的习惯:Host.CreateApplicationBuilder、AddMcpServer、WithStdioServerTransport。它的日志支持比较完整,请求/响应、错误堆栈都能打出来,适合调试和生产。
装包:
dotnet add package McpDotNet配置片段(appsettings.json里放 TaoToken 三件套,避免硬编码):
{ "TaoToken": { "BaseUrl": "https://taotoken.net/api", "ApiKey": "sk-你的Key", "ModelId": "claude-sonnet-4-20250514" }, "Logging": { "LogLevel": { "Default": "Information", "McpDotNet": "Debug" } } }Server 端代码:
using McpDotNet.Server; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; var builder = Host.CreateApplicationBuilder(args); builder.Configuration.AddJsonFile("appsettings.json", optional: false); builder.Services.AddMcpServer() .WithStdioServerTransport() .WithTools(); var app = builder.Build(); await app.RunAsync();工具注册用 DI 方式,把IConfiguration注入进去拿 TaoToken 配置:
using McpDotNet.Server; using Microsoft.Extensions.Configuration; public class FileSearchTool { private readonly IConfiguration _config; public FileSearchTool(IConfiguration config) => _config = config; [McpTool("SearchFiles", "按关键字搜索本地文件")] public List<string> Search( [McpParameter(true, "关键字")] string keyword, [McpParameter(false, "搜索根目录")] string root = "C:\\") { return Directory .GetFiles(root, $"*{keyword}*", SearchOption.AllDirectories) .Take(50) .ToList(); } }mcpdotnet 的日志级别可以通过McpClientOptions或Logging.LogLevel调整。调试阶段把McpDotNet设成Debug,能看到每次工具调用的入参和返回,排障非常省事。TaoToken 的 Key 放在appsettings.json里,生产环境建议用环境变量覆盖,别提交到仓库。
3.3 ModelContextProtocol.NET:接口预留多,谨慎用于生产
这个库的定位偏框架,属性化 API 有,但文档不足,WebSocket 等功能还在开发中。如果你只是想快速跑通,不建议首选;但如果你想研究协议扩展或 AOT,可以试。
装包后大致写法:
using ModelContextProtocol.NET; [McpToolType] public static class EchoTool { public static string Echo([McpParameter] string message) => $"Echo: {message}"; } var server = new McpServer(); server.RegisterTool<EchoTool>(); server.Start();它的配置项相对少,TaoToken 三件套一般不在 Server 端直接配,而是由客户端统一走 TaoToken。也就是说,你用这个库时,模型调用通道更多依赖客户端配置,Server 只负责暴露工具。这一点在选型时要清楚:如果你的架构是“Server 内部也要调模型”,这个库目前支持得不够顺手。
三个库的配置差异,用一张表对照更直观:
| 维度 | MCPSharp | mcpdotnet | ModelContextProtocol.NET |
|---|---|---|---|
| 工具注册 | 属性标记,零配置 | DI + WithTools | 属性标记,文档少 |
| 配置方式 | 代码内直接写 | appsettings + DI | 代码内 |
| TaoToken 三件套位置 | 工具方法内读环境变量 | appsettings.json | 多在客户端 |
| 日志 | 基础 | 详细,可调级别 | 不完善 |
| 适合场景 | 快速原型 | 生产服务 | 协议实验 |
4. 验证请求:本地跑通并确认工具被调用
配置写完,必须本地验证,别直接扔给客户端。验证分两步:先确认 MCP Server 能启动,再确认工具能被调用、TaoToken 通道能返回。
第一步,编译并启动。以 MCPSharp 为例:
dotnet build dotnet run如果 Server 走 stdio,启动后不会打印太多东西,这是正常的。你可以用 MCP 客户端或官方 inspector 连上去看工具列表。mcpdotnet 因为日志详细,启动后能看到类似McpServer started、Tools registered: 2的输出。
第二步,验证 TaoToken 通道。单独写一个小测试,确认 Key 和 Base URL 没问题:
using System.Net.Http.Headers; using System.Text; using System.Text.Json; var apiKey = Environment.GetEnvironmentVariable("TAOTOKEN_API_KEY"); var baseUrl = "https://taotoken.net/api"; var payload = new { model = "claude-sonnet-4-20250514", messages = new[] { new { role = "user", content = "回复 OK 两个字母" } } }; var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/v1/chat/completions"); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); req.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); var resp = await new HttpClient().SendAsync(req); Console.WriteLine(await resp.Content.ReadAsStringAsync());成功的话,你会看到 JSON 里choices[0].message.content是OK。这一步过了,说明三件套没问题,再回到 MCP Server 里调用就不会因为 Key 报错。
第三步,端到端验证。在客户端(比如 Cline 或 Claude Code)里配置这个 MCP Server,然后问一句“帮我算 5 加 3”。如果工具注册正确,客户端会调用Add,返回 8。如果 Server 内部还调了 TaoToken 做总结,日志里应该能看到两次请求:一次是客户端到 Server,一次是 Server 到 TaoToken。
实测下来,最容易出问题的是 stdio 传输的编码和换行。如果你在 Windows 上跑,确保输出用 UTF-8,别混入 BOM,否则客户端解析会失败。
5. 常见错排查:401、local proxy failed、reading choices、OAuth
这一节按真实报错来,遇到直接对号入座。
401 Unauthorized。九成是 Key 没读到或格式不对。检查TAOTOKEN_API_KEY是否真的注入到进程环境里,PowerShell 里$env:只在当前会话有效。另外确认请求头是Authorization: Bearer sk-...,别漏了Bearer前缀。如果 Key 是从控制台复制的,注意别带空格。
local proxy failed。这个报错通常出现在客户端侧,意思是客户端连不上你配置的本地 MCP Server。先确认 Server 进程在跑,端口没被占用。stdio 模式下不存在端口问题,但如果你用了 HTTP/SSE 传输,检查localhost:端口是否可达。用curl http://localhost:5000/health这类探活接口测一下。另外,客户端配置里的命令路径要写绝对路径,相对路径在不同工作目录下会找不到。
reading choices 相关报错。这通常发生在解析 TaoToken 返回的 JSON 时。原因可能是:请求根本没成功(返回的是错误对象,没有choices字段),或者模型 ID 写错导致返回结构不同。先打印原始响应体,确认choices存在。如果返回的是{"error": {...}},那就是 Key 或模型 ID 的问题。还有一种情况是流式返回没处理完就解析,建议先用非流式验证。
OAuth 相关报错。如果你用的是 Claude Code 这类客户端,它可能默认走 OAuth 登录而不是 API Key。这时候要在客户端配置里显式指定 Base URL 和 Key,别让它走默认的 OAuth 流程。Claude Code 的接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=claude_code&utm_campaign=rewrite ,里面有 Base URL、Key、Model ID 三件套的填法。如果你用的是 CC Switch 或 Cline 的 MCP 配置,同样要确保三件套齐全:Base URL 填https://taotoken.net/api,Key 填sk-...,Model ID 填你实际用的。
再补一个容易忽略的:工具没被发现。MCPSharp 里检查[McpTool]和[McpFunction]是否都标了,类是否是public;mcpdotnet 里检查WithTools()有没有调用,工具类有没有注册进 DI。改完重启 Server,别热重载,MCP 连接状态可能不会刷新。
6. 选型建议与统一 Key 接入的收尾
回到最初的问题:谁才是 AI 助手的最佳搭档?我的判断是分场景的。如果你要在一天内把现有 .NET 方法变成 AI 可调用的工具,MCPSharp 的属性化 API 最省事,代码量最少。如果你要做的是一个长期运行、需要排障和并发控制的 MCP 服务,mcpdotnet 的 Host + DI + 详细日志更靠谱。ModelContextProtocol.NET 目前更适合观望和实验,等它的 WebSocket 和文档补齐再上生产。
不管选哪个,TaoToken 的统一 Key 接入都能帮你省掉“每个模型一套配置”的麻烦。三件套记住:Base URLhttps://taotoken.net/api,Key 从控制台拿,Model ID 按需切换。需要创建 Key 就去 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite ,想先试模型就去 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite ,长期做编码 Agent 可以看 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。
最后给你一个实用技巧:把三个库的 Server 都写成独立的可执行项目,客户端配置里按需切换。这样你可以在同一个 AI 助手里对比它们的实际表现,而不是只看文档。跑通一个之后,另外两个的迁移成本其实很低,因为 MCP 协议本身是统一的,变的只是 C# 侧的写法。