当前位置: 首页 > news >正文

构建你的 MCP 能力层:.NET 9 + SK 的系统方案

环境准备与基线项目(.NET 9 + SK + MCP)

目标:搭建最小可运行的 .NET 控制台,引用 SK 与 MCP,完成一次 MCP Ping 健康检查(Stdio 与 SSE/HTTP 各跑通一次),并为后续端到端示例打下基线。


1.1 创建解决方案与基线项目

# 安装 .NET 9 SDK(略)mkdir SkMcp && cd SkMcpdotnet new sln -n SkMcp# 创建三个项目:
# 1) 最小可运行基线(含 Ping 冒烟测试)
# 2) MCP Server(Stdio/HTTP 两种宿主)
# 3) SK 客户端(演示“把 MCP 工具当作 SK 函数”)mkdir -p src/SkMcp.Baseline src/SkMcp.Server src/SkMcp.SkClient tests/SkMcp.End2Enddotnet new console -n SkMcp.Baseline -o src/SkMcp.Baselinedotnet new console -n SkMcp.Server   -o src/SkMcp.Serverdotnet new console -n SkMcp.SkClient -o src/SkMcp.SkClientdotnet new xunit   -n SkMcp.End2End  -o tests/SkMcp.End2End# 解决方案引用dotnet sln add src/*/**.csproj tests/*/**.csproj

结构建议

  • src/*tests/* 分离,后者用于 E2E 冒烟(Ping、ListTools、CallTool 回显)。
  • 为每个 Server 建 docs/ 示例资源目录,便于 resources 流程(第 6 章)。

版本固定策略:以上 dotnet add 仅添加包名,实际生效版本由根目录 Directory.Packages.props 锁定(Microsoft.SemanticKernel=1.65.0McpDotNet.Extensions.SemanticKernel=0.0.1-preview-04)。构建管线中启用 -p:ContinuousIntegrationBuild=true-warnaserror,确保出现不兼容 API 时能第一时间在 CI 上失败而非运行期暴露问题。

版本与兼容性建议

  • MCP SDK 仍在快速迭代,推荐在根目录使用 Directory.Packages.props 锁定主次版本,避免传递依赖“偷偷升级”。
  • McpDotNet.Extensions.SemanticKernel 与 SDK 存在配套关系:如遇 API 不匹配,优先以 MCP SDK 版本为锚回退/前进。

建议的 Directory.Packages.props 片段(版本固定)

<Project><ItemGroup><PackageVersion Include="ModelContextProtocol" Version="0.3.0-preview.*" /><PackageVersion Include="McpDotNet.Extensions.SemanticKernel" Version="0.0.1-preview-04" /><PackageVersion Include="Microsoft.SemanticKernel" Version="1.65.0" /></ItemGroup>
</Project>

说明:构建时将严格解析到以上版本;如需升级,请同步验证扩展包与 SDK 的 API 兼容性,再做渐进发布(先预发环境,再生产灰度)。

 <Project><ItemGroup><PackageVersion Include="ModelContextProtocol" Version="0.3.0-preview.*" /><PackageVersion Include="McpDotNet.Extensions.SemanticKernel" Version="0.3.*" /><PackageVersion Include="Microsoft.SemanticKernel" Version="1.*" /></ItemGroup></Project>

1.3 .env 与本地机密管理(User Secrets)

开发期:

  • 使用 User Secrets + IConfiguration,避免把密钥写入源码;
  • appsettings.Development.json 仅放非敏感默认值;
  • 机密键命名约定:OpenAI:ApiKeyGitHub:Token:RepoRead 等。

生产期:

  • 云端使用 Key Vault/Secrets Manager + 托管标识;
  • 容器仅挂载只读 Secret,不要.env bake 进镜像;
  • 最小权限:OpenAI 仅 apiKey;GitHub PAT 起步 repo:readissues:read

1.4 MCP “Ping” 最小验证(Stdio 与 SSE/HTTP)

新增一个最小冒烟控制台(或在 Baseline 中内置):

  • Stdio:通过 npx/Node 启动本地示例 server(如 server-everything),客户端 PingAsync + ListTools + CallTool("echo")
  • SSE/HTTP:对等流程;
  • 跨平台提示(Windows 常见问题):若出现 ENOENT/找不到 npx,请使用 Node 的绝对路径where npx 结果;
  • 长连接保活:定期 PingAsync
  • E2E 测试点
    • Ping 成功;
    • ListTools 至少包含 echo
    • CallTool("echo", { message: "hello" }) 返回包含 hello 的文本内容。

关于传输:SSE 仍可用,但更推荐 Streamable HTTP(第 2.4、4.2 详述)。


MCP 概念速通与协议选型(强化到 Streamable HTTP)

2.1 核心概念

  • Tools:由 MCP Server 暴露的可调用能力(读/写/搜索等)。
  • Resources:可检索/读取的外部资料(文档、代码、数据),支持分页与哈希标识。
  • Prompts:可复用提示模板,由 Server 声明,客户端可发现与调用。
flowchart LRsubgraph Host[LLM Host / Orchestrator]SK[Semantic Kernel]Behavior[FunctionChoiceBehavior Policies]endsubgraph MCPClient[MCP Client]Discovery[List Tools/Resources/Prompts]Invoke[call_tool]endsubgraph MCPServers[MCP Servers]S1[Server A e.g., GitHub]S2[Server B Doc/FS/DB]endsubgraph Backends[External Systems]GH[GitHub API]FS[File Store]DB[Database]endSK-->Behavior-->Discovery-->InvokeInvoke-->S1-->GHInvoke-->S2-->FSS2-->DB
sequenceDiagramautonumberparticipant User as User/Agentparticipant SK as SK (Kernel)participant MCPc as MCP Clientparticipant MCPs as MCP Serverparticipant Ext as External SystemUser->>SK: 触发任务(含系统/用户提示)SK->>MCPc: 列举可用工具(ListTools/Prompts/Resources)MCPc-->>SK: 工具与参数 SchemaSK->>SK: 策略评估(白名单/置信度/成本)SK->>MCPc: call_tool(tool, args)MCPc->>MCPs: 执行(Streamable HTTP/SSE/Stdio)MCPs->>Ext: 调用外部系统(幂等/超时/重试)Ext-->>MCPs: 结果/分页数据MCPs-->>MCPc: 流式增量内容(可包含 resource link)MCPc-->>SK: 聚合结果SK-->>User: 最终回答(含引用与可追溯信息)

2.4 传输协议选型

  • Stdio:本地开发/快速试验,零网络依赖。
  • SSE:历史方案,适合流式文本下行。
  • Streamable HTTP(推荐):统一 HTTP 请求/响应 + 可选事件流,覆盖一次性结果与长任务输出;同一服务可既支持传统 HTTP,也支持事件流端点,便于渐进迁移。

迁移建议:HTTP 宿主默认启用 Streamable HTTP,保留 SSE 兼容端点若干版本。


作为 MCP Client——在 SK 中“接工具”

3.1 方式 A:用扩展包“一行接入”(Stdio & SSE/HTTP)

// Program.cs 片段
var builder = Kernel.CreateBuilder();
// ... 配置 OpenAI/AzureOpenAI 等模型// 以 Stdio 形式连接某 MCP Server(示例:server-everything)
await builder.AddMcpFunctionsFromStdioServerAsync(kernel:null, // 可省略,使用 builder 内核serverExecutablePath:"/absolute/path/to/node", // Windows 下建议绝对路径serverArgs: new [] { "npx", "-y", "@modelcontextprotocol/server-everything" },namePrefix: "everything_",            // 避免与其他 Server 同名工具冲突includedPlugins: null,includedFunctions: null,cancellationToken: ct);var kernel = builder.Build();// 打印工具清单(调试)
foreach (var f in kernel.GetFunctions())
{Console.WriteLine($"{f.PluginName}.{f.Name} -> {f.Description}");
}// 白名单方式减少“误触发”
var behavior = FunctionChoiceBehavior.Auto(allowance: 3,functions: kernel.GetFunctions().Where(f => f.Name.StartsWith("http_") || f.Name == "echo"));

实践加强

  • 限流/超时:为高成本工具(如 http/get)套一层包装,设置超时、最大返回大小(KB/MB)与调用间隔(冷却时间)。
  • 系统提示:在 system 中明确“仅在需要时才调用工具,并优先使用指定白名单”。

3.2 方式 B:纯 SDK(“裸接入”)把 MCP 工具转为 SK 函数

要点:

  • JSON schema → SK 参数:对 object/array 入参,优先整体 JSON 字符串透传,减少 LLM 构造复杂结构的出错率;
  • Content 聚合call_tool 返回可能包含 textresource 链接,注意把 ResourceLink 也回传给终端应用(用于可追溯)。

作为 MCP Server——用 C# 暴露你自己的工具

4.1 Stdio 版本(控制台宿主)

// Program.cs(简化)
var server = McpServerBuilder.Create("demo-server").WithToolsFromAssembly(typeof(Program).Assembly).WithResources(opts => opts.RootDirectory = "./docs").Build();await server.RunStdioAsync();

建议

  • 每个工具方法都接受 CancellationToken,并在服务器级配置软超时;
  • 输入校验:例如 CsvFilter(string column, string op, string value) 增加列名白名单、最大行数/文件大小限制,避免 OOM;
  • 日志分流:业务日志走 stdout、诊断/调试走 stderr,方便客户端区分。
graph TB Client\[Client/Browser/Agent] --> Proxy\[Reverse Proxy/Nginx] Proxy --> Kestrel\[ASP.NET Core (Kestrel)] Kestrel -->|/mcp (HTTP)| EndpointHTTP\[HTTP Endpoint] Kestrel -->|/mcp/events (SSE)| EndpointSSE\[SSE/Events] EndpointHTTP --> Tools\[Tools] EndpointHTTP --> Resources\[Resources] EndpointSSE --> Tools EndpointSSE --> Resources

4.3 容器化(Dockerfile)

# 多阶段构建
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish src/SkMcp.Server/SkMcp.Server.csproj -c Release -o /outFROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /app
COPY --from=build /out .
# 只读挂载机密;不要复制 .env 到镜像
ENTRYPOINT ["dotnet", "SkMcp.Server.dll"]

4.4 部署与运维(systemd / Nginx / 健康检查)

  • 健康检查:除 MCP 通道 Ping 外,暴露独立 /healthz 区分进程活性与业务健康;
  • 日志与指标:结构化日志(JSON)+ Prometheus 指标(QPS、失败率、P95 时延、事件流存活数);
  • 滚动升级:灰度/金丝雀,回滚策略与版本锚定。

端到端 A:开发者 GitHub 助手

5.1 选用官方 GitHub MCP Server

  • 优先使用官方镜像/源码运行(Stdio 或远端 HTTP);
  • 从只读权限起步(repo:readissues:read),确认调用路径稳定再逐步放开写权限;
  • search issues 之类高频工具加冷却时间分页上限

5.2 在 SK 侧注册 GitHub 工具(扩展包写法)

await builder.AddMcpFunctionsFromSseServerAsync(serverUrl: new Uri("https://your-github-mcp.example/mcp"),namePrefix: "gh_",includedFunctions: new [] { "search_issues", "get_repo" },cancellationToken: ct);

端到端 B:企业知识检索助手(Resources)

6.1 Server 侧资源暴露

  • 大文件/大目录务必强制分页(按字节或行数),返回 cursor/next
  • 明确 contentType 与编码,例如 text/markdown; charset=utf-8
  • 返回 resourceUrihash/etag,便于可追溯与缓存控制。

6.2 客户端(SK)检索与回答(ReAct 思路)

  • 将“检索→调用→回答”的中间观察写入隐藏槽位或日志;
  • 对用户输出统一以“三句话摘要 + 引用 URI”收尾;
  • 对模型的工具选择策略使用白名单 + 置信阈值,避免“为了调用而调用”。

端到端 C:数据处理流水线(Prompts + Tools)

7.1 在 MCP Server 注册可复用 Prompt

  • 将规范化的数据清洗/汇总模板以 Prompt 形式暴露,参数化日期、项目名等;
  • 对 Prompt 做版本号管理(如 v2025.09)以便回溯。
flowchart TDT0[触发: {date}:{project}] --> T1[检索与预清洗 (MCP: CsvClean/CsvFilter/HttpGet)]T1 -->|失败: 重试N次→死信| DLQ[Dead Letter Queue]T1 --> T2[聚合与特征化 (MCP: Prompt v2025.09)]T2 --> T3[生成报告草稿 (SK: LLM with FunctionChoiceBehavior)]T3 -->|资源引用与哈希| T4[落盘→命名含内容哈希]T4 --> T5[发布/通知/审计]

文档化、学习路径与 FAQ(扩展)

8.1 学习路径

  1. 跑通第 1 章最小冒烟(Stdio + SSE/HTTP)→ 2) 第 3 章把工具接入 SK → 3) 任一端到端示例(5/6/7 章)→ 4) 生产化与安全(4.3/4.4)。

8.2 踩坑手册

  • 代理与事件流:公司网关可能“截流”事件流,需在反代层 proxy_buffering off 并放宽空闲超时;
  • 同名工具冲突:不同 Server 暴露同名工具时,在注册时加 namePrefix 或放入不同插件命名空间;
  • CSV 换行混用\r\n/\n 混用会导致“按行分页错位”,统一转 LF 后再分页;
  • Windows npx 不可见:使用 Node 绝对路径或 where npx 结果;
  • 模型“过度调用工具”:白名单 + 明确系统提示 + 冷却时间控制。
http://www.hskmm.com/?act=detail&tid=14815

相关文章:

  • pl/sql使用
  • PLC中的运动控制 - (二)基本控制指令MC_Power,MC_Stop,MC_Halt
  • FOC之电机模型
  • 使用shell脚本一键部署docker及docker-compose环境
  • paddleOCR 图片识别
  • 使用命令行powershell修改系统变量
  • 数据全生命周期安全建设方案推荐:双轮驱动架构的实践与创新
  • 赋能智慧水利:国标GB28181平台EasyGBS在农业水文监控中的落地实践
  • VS依赖项显示黄色感叹号、红色叉叉,NU1101找不到包异常情况处理方案
  • 噬菌体展示技术原理深度解析:从基因型-表型偶联到亲和筛选的核心逻辑
  • AT_arc197_e [ARC197E] Four Square Tiles
  • 不限速网盘盘点,五款免费网盘综合对比
  • 日记2
  • RTK精度和时间 - MKT
  • LeetCode-100.相同的树
  • ubuntu安装minio并切换数据存储目录
  • 学习笔记508— 威联通安装使用Zerotier One
  • Java 语法糖大揭秘:让代码更甜更高效的幕后功臣 - 教程
  • Linux命令
  • 树上莫队
  • 比余额宝收益高的低风险短期理财工具-银行同业存单
  • 陇剑杯2025 决赛-ShellDecoder
  • Springcloud gateway笔记
  • AT_arc122_e [ARC122E] Increasing LCMs
  • C++ 锁
  • 飞书对程序员下手了,0 代码生成各类系统!!(附保姆级项目实战教程)
  • Adaptix C2:跨平台渗透测试与对抗仿真框架
  • 国标GB28181软件EasyGBS网页直播平台在邮政快递场景的落地与应用
  • sql统计一个字段各个值各有多个个的方法
  • WBS、甘特图、关键路径……项目计划的五大核心概念一文全懂