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

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

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


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

bash 复制代码
# 安装 .NET 9 SDK(略)

mkdir SkMcp && cd SkMcp

dotnet 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.End2End

dotnet new console -n SkMcp.Baseline -o src/SkMcp.Baseline

dotnet new console -n SkMcp.Server   -o src/SkMcp.Server

dotnet new console -n SkMcp.SkClient -o src/SkMcp.SkClient

dotnet 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 片段(版本固定)

xml 复制代码
<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 兼容性,再做渐进发布(先预发环境,再生产灰度)。

xml 复制代码
 <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 LR subgraph Host[LLM Host / Orchestrator] SK[Semantic Kernel] Behavior[FunctionChoiceBehavior Policies] end subgraph MCPClient[MCP Client] Discovery[List Tools/Resources/Prompts] Invoke[call_tool] end subgraph MCPServers[MCP Servers] S1[Server A e.g., GitHub] S2[Server B Doc/FS/DB] end subgraph Backends[External Systems] GH[GitHub API] FS[File Store] DB[Database] end SK-->Behavior-->Discovery-->Invoke Invoke-->S1-->GH Invoke-->S2-->FS S2-->DB

User/Agent SK (Kernel) MCP Client MCP Server External System 触发任务(含系统/用户提示) 1 列举可用工具(ListTools/Prompts/Resources) 2 工具与参数 Schema 3 策略评估(白名单/置信度/成本) 4 call_tool(tool, args) 5 执行(Streamable HTTP/SSE/Stdio) 6 调用外部系统(幂等/超时/重试) 7 结果/分页数据 8 流式增量内容(可包含 resource link) 9 聚合结果 10 最终回答(含引用与可追溯信息) 11 User/Agent SK (Kernel) MCP Client MCP Server External System

2.4 传输协议选型

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

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


作为 MCP Client------在 SK 中"接工具"

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

csharp 复制代码
// 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 版本(控制台宿主)

csharp 复制代码
// 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)

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 /out

FROM 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 工具(扩展包写法)

csharp 复制代码
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 TD T0[触发: {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 结果;
  • 模型"过度调用工具":白名单 + 明确系统提示 + 冷却时间控制。

8.3 外链与版本跟进(放到 README 顶部也可)

  • MCP 规范与 Streamable HTTP 概述
  • MCP C# SDK(NuGet / GitHub)
  • Semantic Kernel 函数选择与函数白名单
  • MCP × SK 扩展包(仓库与 NuGet)
  • GitHub MCP Server(仓库与镜像)
相关推荐
RD_daoyi1 天前
Google核心算法不再通知!全年持续滚动更新
大数据·服务器·前端·网络·搜索引擎·.net
他们叫我 悦儿遥遥雨1 天前
.NET 8 Web开发入门(六):Blazor 全栈开发——告别 JavaScript 焦虑
前端·javascript·.net
深爱水瓶 血影S狂风1 天前
Linux.NET学习手记(2)
linux·学习·.net
weipt1 天前
springboot项目运行的几种方式
javascript·css·html
贾天佑忆月 迷失的昵1 天前
.NET Web开发技术简单整理
前端·.net
杰佛史彦明 本王是暴君1 天前
.NET PDB文件到底是什么?
.net
呼噜想睡觉2 天前
Flex弹性布局
css·html·css3
AI行业学习2 天前
Claude Code + cc-switch + Git + Node.js 全套下载+安装+配置完整版
开发语言·git·python·前端框架·node.js·html·notepad++
界面开发小八哥2 天前
界面控件DevExpress Office & PDF File v26.1新版亮点 - 全新的条码生成API
pdf·.net·devexpress·ui开发·文档控件·.net 10
并不喜欢吃鱼2 天前
一.前端web开发:零基础吃透 HTML5 核心知识
前端·html·html5