Bitzsoft.Integrations.McpServer
1.1.0
dotnet add package Bitzsoft.Integrations.McpServer --version 1.1.0
NuGet\Install-Package Bitzsoft.Integrations.McpServer -Version 1.1.0
<PackageReference Include="Bitzsoft.Integrations.McpServer" Version="1.1.0" />
<PackageVersion Include="Bitzsoft.Integrations.McpServer" Version="1.1.0" />
<PackageReference Include="Bitzsoft.Integrations.McpServer" />
paket add Bitzsoft.Integrations.McpServer --version 1.1.0
#r "nuget: Bitzsoft.Integrations.McpServer, 1.1.0"
#:package Bitzsoft.Integrations.McpServer@1.1.0
#addin nuget:?package=Bitzsoft.Integrations.McpServer&version=1.1.0
#tool nuget:?package=Bitzsoft.Integrations.McpServer&version=1.1.0
Bitzsoft.Integrations.McpServer
基于官方 MCP C# SDK 的安全 Client/Server 集成。包名为兼容既有命名保留
McpServer,实际同时提供 Streamable HTTP、stdio 客户端以及 HTTP、stdio 服务端。
适用范围
- 将受信 MCP 工具接入 Microsoft Agent Framework 或
Microsoft.Extensions.AI; - 把现有 ASP.NET Core 业务能力显式发布为 MCP 工具;
- 启动经过审批的本地 stdio MCP 服务;
- 按租户、地域、环境和凭据名称解析 MCP 访问凭据。
目标框架为 net8.0;net10.0。MCP 官方 SDK 不支持 .NET 5,因此老系统应把 MCP/Agent 能力部署为独立 .NET 8/10 服务,再通过受控 HTTP 边界调用。
安装
dotnet add package Bitzsoft.Integrations.McpServer
安全默认值
本封装采用默认拒绝策略:
- 客户端必须配置非空
AllowedTools,连接成功后只返回白名单工具; - HTTP 必须配置
AllowedHosts;远程地址必须使用 HTTPS; - URL 禁止携带用户名、密码、query 或 fragment;
- 默认阻止远程地址解析到私网、链路本地、共享地址、文档/基准测试地址和特殊网段, 并固定首次校验得到的 IP,降低 SSRF 与 DNS 重绑定风险;
- loopback 主机必须只解析到 loopback IP,避免被污染的主机解析把本地配置导向远端;
- HTTP Bearer Token 通过
IIntegrationCredentialResolver按当前IntegrationContext解析,不进入 Options、配置文件或日志; - stdio 命令必须是白名单中的绝对路径,不通过 shell 拼接参数;
- stdio 子进程不继承完整父进程环境,只传官方安全基础环境和显式凭据字段;
- 服务端不扫描程序集、不附带示例工具,只有显式调用
WithTools<T>()的类型会被公开; - HTTP 服务端自动加入 MCP 授权过滤器,但宿主仍必须为
MapMcp()端点配置认证授权。
AllowPrivateNetwork = true 只应对经过审批的企业内网 MCP 服务开启;它不会关闭主机白名单、HTTPS、禁重定向或 DNS 固定。客户端当前提供 Bearer Token;OAuth 动态授权、mTLS 或企业代理由宿主使用官方 MCP SDK 定制传输。
HTTP 客户端
注册
using Bitzsoft.Integrations.McpServer;
using Bitzsoft.Integrations.McpServer.Models;
// 命名客户端配置只保存非敏感连接策略。
services.AddBitzMcpHttpClient("knowledge", options =>
{
options.Endpoint = new Uri("https://mcp.example.com/mcp");
options.ProviderId = "knowledge";
options.CredentialName = "production";
options.AllowedHosts.Add("mcp.example.com");
options.AllowedTools.Add("search_knowledge");
options.AllowedTools.Add("read_document");
options.RequireAuthentication = true;
});
生产宿主应实现 IIntegrationCredentialResolver 并连接 Vault、KMS 或云密钥服务。开发测试可以显式使用进程内 Store:
// 仅开发/测试:生产环境替换为 Vault、KMS 或云密钥服务。
services.AddInMemoryIntegrationCredentials();
// 凭据键必须与实际调用时的 IntegrationContext 完全匹配。
var context = new IntegrationContext(
tenantId: "tenant-a",
region: "cn-east",
environment: "production");
var key = IntegrationCredentialKey.FromContext(
context,
"MCP:knowledge",
"production");
using var credential = new IntegrationCredential(
new Dictionary<string, string>
{
[McpCredentialFieldNames.BearerToken] = developmentToken
});
credentialStore.Set(key, credential);
不要把真实 Token 放入 appsettings.json、环境映射 Options 或日志。进程内 Store 不是生产密钥服务。
连接并交给 Agent
每次操作必须先设置租户上下文。McpClientConnection 持有底层会话,工具仍依赖该会话,因此必须在 Agent 完成调用后再释放连接。
// 当前租户上下文是凭据解析的强制输入。
using var contextScope = contextAccessor.Push(
new IntegrationContext("tenant-a", correlationId: traceId));
await using var connection = await mcpClientFactory.ConnectHttpAsync(
"knowledge",
cancellationToken);
// AgentTools 已转换为 Agent 构造函数需要的 IList<AITool>。
IList<AITool> tools = connection.AgentTools;
推荐按请求或一次 Agent Run 创建连接,不要跨租户缓存连接或工具。白名单中有工具未被远端公开时连接会失败,避免服务端能力漂移被静默忽略。
完整 HTTP Client + Agent 示例
以下示例使用开发 Token,并确保 MCP 连接覆盖整个 Agent Run:
using Bitzsoft.Integrations.AI;
using Bitzsoft.Integrations.Core;
using Bitzsoft.Integrations.McpServer;
using Bitzsoft.Integrations.McpServer.Models;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
// 仅开发/测试;生产环境注册安全凭据解析器。
services.AddInMemoryIntegrationCredentials();
// 注册租户感知模型;模型密钥同样不进入 Options。
services.AddBitzChatClient(options =>
{
options.ProviderId = "deepseek-dev";
options.ProfileId = "deepseek";
options.ModelId = "deepseek-flash";
});
services.AddBitzMcpHttpClient("knowledge", options =>
{
options.Endpoint = new Uri("https://mcp.example.com/mcp");
options.ProviderId = "knowledge";
options.CredentialName = "development";
options.AllowedHosts.Add("mcp.example.com");
options.AllowedTools.Add("search_knowledge");
options.RequireAuthentication = true;
});
await using var provider = services.BuildServiceProvider(
new ServiceProviderOptions { ValidateScopes = true });
// 为 tenant-a 写入 MCP:knowledge 的开发 Bearer Token。
var credentialStore = provider.GetRequiredService<
InMemoryIntegrationCredentialStore>();
// 写入模型凭据 AI:deepseek-dev。
using (var credential = new IntegrationCredential(
[
new(AICredentialFieldNames.ApiKey, "<开发环境模型 API Key>")
]))
{
credentialStore.Set(
new IntegrationCredentialKey(
tenantId: "tenant-a",
providerKey: "AI:deepseek-dev",
environment: IntegrationEnvironments.Development),
credential);
}
// 写入 MCP 凭据 MCP:knowledge。
using (var credential = new IntegrationCredential(
[
new(McpCredentialFieldNames.BearerToken, "<开发环境 Bearer Token>")
]))
{
credentialStore.Set(
new IntegrationCredentialKey(
tenantId: "tenant-a",
providerKey: "MCP:knowledge",
environment: IntegrationEnvironments.Development,
credentialName: "development"),
credential);
}
using var scope = provider.CreateScope();
var contextAccessor = scope.ServiceProvider.GetRequiredService<
IIntegrationContextAccessor>();
using (contextAccessor.Push(new IntegrationContext(
tenantId: "tenant-a",
environment: IntegrationEnvironments.Development)))
{
var factory = scope.ServiceProvider.GetRequiredService<
IMcpClientFactory>();
// connection 必须比 Agent 和它持有的 MCP tools 活得更久。
await using var connection = await factory.ConnectHttpAsync("knowledge");
var chatClient = scope.ServiceProvider.GetRequiredService<IChatClient>();
var innerAgent = new ChatClientAgent(
chatClient,
instructions: "只能使用已批准的只读知识工具。",
name: "knowledge-agent",
description: "查询租户知识库",
tools: connection.AgentTools);
// 即使当前白名单只有只读工具,也保留官方审批中间件。
AIAgent agent = new ToolApprovalAgent(innerAgent);
var response = await agent.RunAsync("查询差旅报销标准。");
Console.WriteLine(response.Text);
}
stdio 客户端
stdio 适合本机受控工具。不要允许用户输入决定 Command 或拼接 Arguments。
// Command 和白名单都必须是管理员部署的绝对路径。
services.AddBitzMcpStdioClient("local-files", options =>
{
options.Command = "/opt/company/mcp/files-server";
options.AllowedExecutablePaths.Add("/opt/company/mcp/files-server");
options.Arguments.Add("--read-only");
// 工作目录必须是部署时已存在的绝对路径。
options.WorkingDirectory = "/srv/approved-documents";
options.AllowedTools.Add("read_approved_file");
options.ProviderId = "local-files";
options.RequireCredential = true;
// 这里只保存“环境变量名 -> 凭据字段名”,不保存 Token 值。
options.CredentialEnvironmentVariables["FILES_ACCESS_TOKEN"] =
"AccessToken";
});
CredentialEnvironmentVariables 的 key 是子进程环境变量名,value 是凭据 Store 中的字段名,字典本身不保存凭据值。若服务不需要凭据,保持 RequireCredential = false 并让映射为空。
// stdio 进程也按当前租户解析凭据;不要跨请求缓存 connection。
using var contextScope = contextAccessor.Push(
new IntegrationContext("tenant-a"));
await using var connection = await mcpClientFactory.ConnectStdioAsync(
"local-files",
cancellationToken);
Streamable HTTP 服务端
工具必须显式注册。工具方法应再次执行租户、资源和业务权限检查,不能把“模型决定调用”视为授权。
using System.ComponentModel;
using Microsoft.AspNetCore.Authorization;
using ModelContextProtocol.Server;
[McpServerToolType]
public sealed class KnowledgeTools(IKnowledgeService knowledge)
{
[McpServerTool(Name = "search_knowledge")]
[Description("Search approved tenant knowledge.")]
[Authorize(Policy = "McpKnowledgeRead")]
public Task<SearchResult> SearchAsync(
string query,
CancellationToken cancellationToken)
// 业务服务内部仍需校验当前租户、用户和资源权限。
=> knowledge.SearchAsync(query, cancellationToken);
}
// 只显式公开 KnowledgeTools,不扫描程序集。
builder.Services
.AddBitzMcpHttpServer(options =>
{
options.ServerName = "company-knowledge";
options.ServerVersion = "1.0.0";
options.Instructions = "Read-only access to approved knowledge.";
})
.WithTools<KnowledgeTools>();
var app = builder.Build();
// MCP 端点必须同时配置认证和授权策略。
app.MapMcp("/mcp").RequireAuthorization("McpClient");
生产端点还应配置 TLS、受众和 issuer 校验、速率限制、审计、超时、请求体限制以及网关级防护。对有副作用的工具采用细粒度授权、幂等键和人工审批,不要只依赖自然语言指令。
C3-1 企业级 MCP 服务端双层安全治理与 PAT 认证
针对暴露多租户企业工具的 MCP 服务端,本包内置与 Bitzsoft.Integrations.AI.Governance 联动的全套服务端治理管线:
- 个人访问令牌(PAT)双通道认证(
AddBitzMcpPatAuthentication):支持从 URL 查询参数(?token=/?access_token=)或Authorization: Bearer请求头提取令牌,强制校验可配置明文前缀(默认bitz_mcp_),以 SHA-256 十六进制摘要回调IMcpAccessTokenStore核验有效期与撤销状态,并通过可选IMcpCallerClaimsEnricher注入租户、角色与功能权限码 Claims(不劫持宿主既有 JWT 默认认证方案); - 静态扫描与动态清单热同步注册表(
McpToolPermissionRegistry):扫描标注[McpServerTool]、[McpToolPermission]、[McpPublicTool]、[AIToolDataLevel]、[AIToolRisk]的静态工具,并支持通过SyncPublishedManifest与SyncBlacklist同步动态工具清单及平台全局硬阻断黑名单(推进GovernanceEpoch纪元号); - 两层请求过滤器(
AddBitzMcpGovernanceFilters):- 第一层
tools/list可见性裁剪(McpToolListVisibilityFilter):合并IMcpDynamicToolRuntime动态工具后,按默认拒绝(Fail-Closed)、平台黑名单、租户级启停开关(IMcpTenantToolGovernanceResolver)、外部 MCP 通道高敏数据(AIDataLevel.Sensitive/L2)硬阻断、网页同源scope=Web校验及功能权限码 OR 匹配原地裁剪工具列表;治理配置读取失败时对AIToolRiskLevel.Commit及以上写风险工具自动 Fail-Closed 熔断剔除; - 第二层
tools/call调用门禁与审计(McpToolCallAuthorizationGuard):二次复核平台黑名单、租户熔断、高敏外发禁令与 RBAC 权限,自动桥接McpAmbientToolCallContext与IHttpContextAccessor,并将成功执行与安全拦截事件写入IMcpToolAuditStore;治理配置读取失败时对写风险工具返回GovernanceUnavailable结构化错误信封(Fail-Closed)。
- 第一层
using Bitzsoft.Integrations.McpServer.Authentication;
using Bitzsoft.Integrations.McpServer.Security;
builder.Services.AddSingleton<IMcpAccessTokenStore, MyDatabaseMcpTokenStore>();
builder.Services.AddBitzMcpPatAuthentication();
builder.Services
.AddBitzMcpHttpServer(options =>
{
options.ServerName = "enterprise-mcp";
options.ServerVersion = "1.0.0";
// 可选自定义超级管理员豁免角色名列表(默认 Admin/System/Administrator/TenantAdmin;置空列表 [] 则完全禁用超管豁免)
options.SuperAdminRoleNames = ["Admin", "TenantAdmin"];
})
.WithTools<KnowledgeTools>()
.AddBitzMcpGovernanceFilters()
.AddBitzMcpExternalHomologousGovernance()
.AddBitzMcpDistributedEventStreamStore();
// 原生 AOT 兼容:显式按工具宿主类型登记静态权限元数据(非 AOT 宿主亦可使用 RegisterAssemblies)
McpToolPermissionRegistry.RegisterToolType<KnowledgeTools>();
角色分词安全边界:
McpToolPermissionEvaluator对角色声明(ClaimTypes.Role/"role")仅按,与;切分,保留含空格复合角色名(如"Admin Assistant"、"Office Administrator")的完整词元,杜绝空格拆词导致的越权提权;对 OAuth2scope/scp声明仍兼容空白分隔词元。
动态工具治理、作用域解析、幂等与 MCP 2.4 原生协议扩展
Bitzsoft.Integrations.McpServer 已完全启用 <IsAotCompatible>true</IsAotCompatible> 与源生成 JSON 序列化上下文(无 MVC 反射耦合),统一提供以下基础治理与协议适配契约:
McpInProcessContextScope.Push(...):零 MVC 依赖的进程内异步作用域,安全传播调用方IServiceProvider与ClaimsPrincipal;McpCandidateAndBlacklistGovernanceEngine:配合IMcpCandidateDiscoverySource、IMcpCandidateStore与IMcpDynamicToolRuntime编排动态候选发现同步、协议命名与权限 Schema 发布校验及平台全局黑名单联动阻断;IMcpToolCatalogPort/IMcpToolPolicyStore:提供只读工具目录投影(RegistryMcpToolCatalogPort)与租户启停策略存储端口(InMemoryMcpToolPolicyStore);IMcpCallerScopeResolver/McpPersonalSelfScopePolicy/McpExternalHomologousGovernanceFilter:提供单调行级数据范围解析、个人范围单复数参数强制锁定、PAT 作用域限权、IAIToolArgumentRewriter链与IAIPendingActionService写操作待办拦截;IMcpIdempotencyGuard:基于Utf8JsonWriter规范排序参数哈希与可插拔IMcpDistributedLockProvider的写操作分布式防重保护;EpochCachedMcpTenantGovernanceResolver&IMcpAccessTokenStore吊销扩展:基于IAICacheEpochCoordinator与AIEpochSingleFlightCache提供纪元一致、单航班防击穿及 Fail-Closed 保障的租户治理配置解析,并支持个人访问令牌本人/管理面即时吊销与全生命周期管理;- MCP 2.4 澄清与事件流断点续传:
McpProtocolHumanConfirmationPort封装无反射ElicitAsync人工确认端口,McpDistributedCacheEventStreamStoreAdapter封装ISseEventStreamStore/DistributedCacheEventStreamStore以支持Last-Event-ID断点续传(零 Redis 硬依赖)。
stdio 服务端
// stdio 服务端只公开显式工具,标准输出保留给 MCP 协议。
services
.AddBitzMcpStdioServer(options =>
{
options.ServerName = "company-local-tools";
options.ServerVersion = "1.0.0";
})
.WithTools<ApprovedLocalTools>();
stdio 服务端是父进程控制的单会话服务。标准输出只能写 MCP 协议消息,应用日志应写入标准错误或其他 Sink。
配置参考
McpHttpClientOptions
| 属性 | 默认值 | 说明 |
|---|---|---|
Endpoint |
https://localhost/mcp |
MCP 绝对地址 |
ProviderId |
default |
凭据 Provider 标识,最终键为 MCP:{ProviderId} |
CredentialName |
default |
凭据名称 |
RequireAuthentication |
true |
是否解析 Bearer Token |
AllowedHosts |
空 | 允许的 DNS 主机精确白名单 |
AllowPrivateNetwork |
false |
是否允许非回环私网 |
AllowedTools |
空 | 可交给模型使用的工具精确白名单 |
TransportMode |
AutoDetect |
Streamable HTTP/SSE 协商方式 |
ConnectionTimeout |
30 秒 | 初始连接超时 |
ClientName / ClientVersion |
Bitzsoft / 1.0.0 | MCP 握手客户端身份 |
McpStdioClientOptions
| 属性 | 默认值 | 说明 |
|---|---|---|
Command |
空 | 可执行文件绝对路径 |
AllowedExecutablePaths |
空 | 可执行文件绝对路径白名单 |
Arguments |
空 | 独立进程参数 |
WorkingDirectory |
空 | 可选绝对工作目录 |
AllowedTools |
空 | 工具精确白名单 |
CredentialEnvironmentVariables |
空 | 环境变量名到凭据字段名映射 |
RequireCredential |
false |
是否要求凭据快照 |
ShutdownTimeout |
5 秒 | 子进程退出等待时间 |
与 Agent Framework 的边界
本包负责 MCP 传输、凭据、端点和工具最小权限;Bitzsoft.Integrations.AgentFramework 负责 Agent 组装与会话。工具调用审批、业务授权、幂等和审计属于宿主业务边界。MCP 连接不能比其所属 AgentSession 更早释放。
常见错误
- 把远端返回的全部工具直接交给模型;
- 在配置文件中保存
Authorization或 API Key; - 对 HTTP 服务调用
WithToolsFromAssembly(); - 允许任意
node、npx、bash或用户输入作为 stdio 命令; - stdio 子进程继承父进程全部环境变量;
- 跨租户复用
McpClientConnection; - 仅靠 Agent Instructions 限制删除、付款、发信等副作用。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Bitzsoft.Integrations.AI.Governance (>= 1.1.0)
- Bitzsoft.Integrations.Core (>= 1.0.5)
- ModelContextProtocol (>= 2.4.0)
- ModelContextProtocol.AspNetCore (>= 2.4.0)
-
net8.0
- Bitzsoft.Integrations.AI.Governance (>= 1.1.0)
- Bitzsoft.Integrations.Core (>= 1.0.5)
- ModelContextProtocol (>= 2.4.0)
- ModelContextProtocol.AspNetCore (>= 2.4.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Bitzsoft.Integrations.McpServer:
| Package | Downloads |
|---|---|
|
Bitzsoft.Integrations.All
Bitzsoft 第三方集成聚合包 — net5.0 包含传统连接器,net8.0+ 额外包含受上游 TFM 限制的 AI 模块 |
|
|
Bitzsoft.Integrations.AI.AspNetCore
ASP.NET Core AI 基础设施包 — 提供零缓冲 SSE/NDJSON 流式写出器(HITL/DryRun/Continuation/FinOps)、源生成 RFC 9457 ProblemDetails 异常映射、HttpContext 身份绑定、多模态与后台任务端点辅助,以及标注 AOT 边界的 MVC 只读工具反射发现与构建器 |
|
|
Bitzsoft.Integrations.AI.Testing
Bitzsoft AI 与 MCP 测试支持包 — 无测试框架锁定的存储端口契约测试基类、进程内测试替身、受控测试时钟与 FDE 黄金评估运行器 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.0 | 0 | 11/14/2026 |
| 1.0.6 | 84 | 11/10/2026 |
| 1.0.5 | 101 | 11/7/2026 |
| 1.0.4 | 211 | 9/23/2026 |
| 1.0.3 | 117 | 9/22/2026 |
| 1.0.2 | 149 | 8/29/2026 |
| 1.0.1 | 204 | 8/3/2026 |
| 1.0.0 | 169 | 8/2/2026 |
| 1.0.0-alpha.10 | 98 | 7/26/2026 |
| 1.0.0-alpha.9 | 88 | 7/12/2026 |
| 1.0.0-alpha.8 | 100 | 7/1/2026 |
| 1.0.0-alpha.7 | 106 | 6/16/2026 |
| 1.0.0-alpha.6 | 98 | 6/16/2026 |
| 1.0.0-alpha.5 | 100 | 6/14/2026 |
| 1.0.0-alpha.3 | 95 | 6/7/2026 |
| 1.0.0-alpha.2 | 89 | 5/29/2026 |
| 1.0.0-alpha.1 | 128 | 5/28/2026 |