XiHan.Framework.Protocols.Mcp
MCP(Model Context Protocol)协议适配器,提供 protocols.mcp@1:把 Expose.Mcp 的操作契约发布为 MCP tool,JSON-RPC 2.0,支持 Streamable HTTP 与 stdio 两种传输。适用于让大模型客户端经同一份契约调用业务操作的场景。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.Protocols.Mcp |
| 环层 | Ring 5(协议与插件) |
| 能力 | 提供 protocols.mcp@1;依赖 kernel.hosting@1 |
| 特性入口 | McpProtocolFeature |
| 配置节 | XiHan:Protocols:Mcp |
| 依赖 | XiHan.Framework.Kernel、XiHan.Framework.Hosting.AspNetCore、XiHan.Framework.Hosting.CommandLine、XiHan.Framework.Localization.Abstractions;共享框架 Microsoft.AspNetCore.App |
| AOT | 兼容(IsAotCompatible) |
| 稳定性 | Preview |
概述
MCP 协议版本 2025-06-18。McpProtocolFeature 登记选项、本包的消息目录、McpServer 与 mcp 命令;服务端在第一次解析时按登记表建 tool 表。tool 名按 {resource}_{verb} 推导;tools/list 的 inputSchema / outputSchema 就是操作的请求 / 响应 Schema,title / description 取消息目录里的 <操作 ID>.title / <操作 ID>.description 并按调用方区域翻译,annotations 由契约推导(只读契约只读且幂等,delete 破坏性,ADR-0041)。
每个 tools/call 以新的调用上下文、在自己的服务作用域里经完整内核管道执行,认证、按契约授权、校验与事务都与 HTTP 上相同;操作失败以 isError: true 的结果返回,文本是 <错误码>: <文案>,不是协议错误。
两种传输:
- Streamable HTTP:
MapXiHanMcp()映射POST /mcp,一条消息一个答复,通知回 202,不开 SSE、不建会话。/mcp经过UseXiHan(),请求凭据在外层认证,凭据无效时整个请求 401。 - stdio:命令行宿主的
mcp命令(McpStdioCommand),stdin / stdout 每行一条 JSON-RPC 消息,日志只写 stderr;stdin 的字节按 UTF-8 解码,与控制台代码页无关(Windows 上重定向的标准输入不按 936、437 等代码页解码,中文参数不会成乱码);答复里的非 ASCII 字符按 JSON 转义成\uXXXX,只含 ASCII,按任何控制台输出代码页写出都是合法的 UTF-8;会话的凭据(--authorization或XIHAN_AUTHORIZATION)、租户、关联、区域与时限取自启动进程的命令行选项与环境变量,与invoke同一套映射,作用于每个tools/call。凭据在每次调用的管道里认证,无效时需要认证的 tool 是isError;选项不合法时退出码 64。
何时使用
要让 MCP 客户端(编程助手、对话应用)调用应用的业务操作时用它。HTTP 传输适合远程服务,stdio 适合客户端在本机以子进程启动的工具;要求权限的操作经 HTTP 传输时由请求头带凭据,经 stdio 时由启动参数或环境变量带凭据。
安装与启用
dotnet add package XiHan.Framework.Protocols.Mcp --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Full 已包含本包。
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Profiles.Standard;
using XiHan.Framework.Protocols.Mcp;
using XiHan.Framework.Protocols.Mcp.Transports;
var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan.UseStandardProfile().UseFeature<McpProtocolFeature>());
var app = builder.Build();
app.UseXiHan();
app.MapXiHanMcp(); // POST /mcp
app.Run();命令行宿主里装配 McpProtocolFeature 并调用 AddXiHanCommandLine() 后,mcp 命令即可用,见命令行宿主。
配置
| 键 | 类型 | 缺省 | 说明 |
|---|---|---|---|
XiHan:Protocols:Mcp:ServerName | string | 宿主的应用名 | initialize 答复的 serverInfo.name |
XiHan:Protocols:Mcp:ServerVersion | string | 框架版本 | serverInfo.version |
XiHan:Protocols:Mcp:Instructions | string | 空 | initialize 答复的 instructions |
XiHan:Protocols:Mcp:Tools:<操作 ID> | string | — | 显式 tool 名,匹配 ^[A-Za-z0-9_-]{1,64}$ |
{
"XiHan": {
"Protocols": {
"Mcp": {
"ServerName": "orders",
"Instructions": "Use orders_list before placing an order.",
"Tools": { "orders.create": "place_order" }
}
}
}
}主要类型
| 类型 | 说明 |
|---|---|
McpProtocolFeature | 特性入口 |
McpProtocolOptions | ServerName、ServerVersion、Instructions、Tools;ToolNameFor(contract) |
Transports.McpEndpointRouteBuilderExtensions | MapXiHanMcp(pattern),缺省 /mcp |
Transports.McpStdioCommand | 命令行宿主的 mcp 命令;会话上下文取自命令行选项与环境变量 |
Transports.McpStdioTransport | RunAsync(server, services, input, output, cancellationToken):按行读写的 stdio 传输;自己托管时按 UTF-8 构造 input(new StreamReader(Console.OpenStandardInput(), Encoding.UTF8)),不要直接用 Console.In |
Server.McpServer | JSON-RPC 服务端:HandleAsync、Tools、FindTool;常量 ProtocolVersion = 2025-06-18、ProtocolVersionHeader = MCP-Protocol-Version |
Server.McpReply | 一条答复与是否为不合法消息(HTTP 400) |
Tools.McpTool | 一个 tool:名字、操作描述、输入 / 输出 Schema、提示 |
Tools.McpToolAnnotations | For(contract):只读、破坏性、幂等提示 |
Tools.McpToolName、Tools.McpToolNameConvention | 名字校验与推导 |
McpErrors | 本包的错误码 |
使用示例
curl -s -X POST localhost:5000/mcp -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
curl -s -X POST localhost:5000/mcp -H "Content-Type: application/json" -H "Authorization: ApiKey dev-alice-key" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"orders_create","arguments":{"name":"widget","amount":3}}}'
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | dotnet run --project framework/samples/SimpleCli -- mcptool 描述的消息键、提示的推导表与 JSON-RPC 错误表见 gRPC、MCP 与 CloudEvents。
行为与限制
tools/list不分页;inputSchema在请求 Schema 的type不是object或没有 Schema 时为{"type":"object"},outputSchema只在响应 Schema 是对象时给出。tools/call成功时content[0].text是响应 JSON,响应是对象时同时给structuredContent。tools/call的调用来源记mcp与 tool 名,HTTP 传输时远端地址、User-Agent 与来源页沿用外层请求(ADR-0043);stdio 的答复只含 ASCII,mcp命令按 UTF-8 解码 stdin、不随控制台代码页,直接调用McpStdioTransport时自己按 UTF-8 构造读取器。- 不开 SSE 流、不建会话(不发
Mcp-Session-Id),GET/DELETE为 405;MCP-Protocol-Version不受支持时 400,缺失按当前版本处理。 - stdio 调用以匿名主体执行,要求权限或登录的操作总是得到
isError结果。
| 错误码 | 情形 | JSON-RPC error.code |
|---|---|---|
PROTOCOLS_VALIDATION_001 | 请求体不是 JSON / 不是 JSON-RPC 2.0 请求 / tools/call 缺 name | -32700 / -32600 / -32602 |
PROTOCOLS_VALIDATION_002 | 协议版本不受支持 | -32600 |
PROTOCOLS_VALIDATION_003 | tool 参数不是 JSON 对象 | -32602 |
PROTOCOLS_VALIDATION_004 | 推导或配置的 tool 名不合法(启动失败) | — |
PROTOCOLS_NOTFOUND_001 | JSON-RPC 方法不受支持 | -32601 |
PROTOCOLS_NOTFOUND_002 | tool 未登记 | -32602 |
PROTOCOLS_CONFLICT_001 | 两个操作得到同一个 tool 名(启动失败) | — |
框架错误码在 error.data.code 里。
相关
- gRPC、MCP 与 CloudEvents、命令行宿主、操作契约
- Hosting.AspNetCore、Hosting.CommandLine、Protocols.Http
- 规范:
spec/protocol/mcp.md《MCP 载体》、RFC-0011《操作契约与 XGI》
