MCP 服务器
一、说明
MCP(Model Context Protocol,模型上下文协议)是 Anthropic 提出的一套开放协议,用于标准化 AI 模型与外部工具、资源之间的交互方式。TouchSocket 提供了完整的 MCP 服务器实现,支持以下两种传输方式:
- Stdio:通过标准输入/输出流进行通信,适用于本地进程间调用(如 Claude Desktop、Cursor 等工具集成)。
- Streamable HTTP:基于 HTTP 协议进行通信,适用于网络服务场景。
MCP 服务器可以向 AI 客户端暴露三类能力:
| 能力 | 特性 | 说明 |
|---|---|---|
| Tools(工具) | [McpTool] | 可被 AI 模型主动调用的函数,支持参数描述和类型推断 |
| Resources(资源) | [McpResource] | 通过 URI 访问的数据资源,支持精确匹配和 URI 模板 |
| Prompts(提示模板) | [McpPrompt] | 预定义的提示消息模板,可接受参数 |
二、特点
- 特性驱动:通过
[McpTool]、[McpResource]、[McpPrompt]特性标注即可完成注册,无需手动配置路由。 - 自动 JSON Schema 生成:工具参数的类型和描述信息会自动生成标准 JSON Schema,无需手动编写。
- 双传输支持:同一套服务定义,可同时以 Stdio 和 HTTP 两种方式发布。
- 基于 RPC 体系:完全集成 TouchSocket 的 Rpc 框架,支持单例、瞬态、区域等生命周期,以及 AOP 拦截、依赖注入等高级功能。
- URI 模板资源:资源支持 RFC 6570 风格的 URI 模板(如
config://server/{key}),实现动态参数匹配。
三、安装
<PackageReference Include="TouchSocket.Mcp" Version="最新版本" />
四、定义 MCP 服务
4.1 基本概念
MCP 服务类需要继承 SingletonRpcServer(或实现 IRpcServer 接口),然后通过特性标注将方法注册为工具、资源或提示模板。
4.2 定义服务类
下面展示了一个包含工具、资源和提示模板的完整 MCP 服务示例:
使用 System.ComponentModel.DescriptionAttribute 为方法和参数添加描述,框架会自动将其注入到 JSON Schema 中,供 AI 模型理解参数含义。
4.3 工具(Tools)
工具使用 [McpTool] 特性标注,可以返回任意可序列化的类型:
- 返回
string、int等基础类型:框架自动包装为文本内容。 - 返回
McpContent或其派生类(McpTextContent、McpImageContent):直接作为内容返回。 - 返回
IEnumerable<McpContent>:返回多条内容。 - 返回
McpCallToolResult:完全自定义结果。
4.4 资源(Resources)
资源使用 [McpResource(uriPattern)] 特性标注,uriPattern 支持两种形式:
- 精确 URI:如
config://server/info,客户端通过完整 URI 访问。 - URI 模板:如
config://server/{key},框架自动提取{key}参数并传入方法。
资源方法支持的返回类型:
- 返回
string:自动包装为文本资源内容。 - 返回
byte[]:自动包装为二进制资源内容(Base64 编码)。 - 返回
McpResourceContent:直接使用。 - 返回
McpReadResourceResult:完全自定义结果。
4.5 提示模板(Prompts)
提示模板使用 [McpPrompt] 特性标注,方法参数作为提示模板的参数(均为字符串类型):
- 返回
McpPromptMessage:单条消息。 - 返回
IEnumerable<McpPromptMessage>:多条消息。 - 返回
McpGetPromptResult:完全自定义结果。
McpPromptMessage 的 Role 字段可取 "user" 或 "assistant"。
五、创建 Stdio 服务器
Stdio 传输方式是 MCP 的标准本地集成方式,适用于 Claude Desktop、Cursor 等工具直接启动子进程进行通信。
McpStdioServer 通过读取 Console.In(标准输入)接收 MCP 消息,通过写入 Console.Out(标准输出)发送响应。因此在 Stdio 模式下,不应在程序中向标准输出打印日志,否则会污染 MCP 通信流。
可通过 McpStdioServerOptions.Reader 和 McpStdioServerOptions.Writer 自定义输入输出流。
5.1 Claude Desktop 集成示例
在 Claude Desktop 的 claude_desktop_config.json 中配置:
{
"mcpServers": {
"my-mcp-server": {
"command": "dotnet",
"args": ["run", "--project", "路径/McpServerConsoleApp"]
}
}
}
六、创建 HTTP 服务器
Streamable HTTP 传输方式适用于网络远程访问场景,基于 TouchSocket 的 HttpService 通过插件方式集成。
McpHttpPlugin 默认监听路径为 /mcp,可通过 options.Path 自定义。
6.1 会话管理
HTTP 模式下,每个 MCP 客户端通过 Mcp-Session-Id 请求头标识会话。服务器自动为首次连接的客户端分配会话 ID,并在 DELETE 请求时销毁会话。
七、注册服务
7.1 注册服务类
使用 AddRpcStore 方法注册 MCP 服务类,与 TouchSocket 其他 RPC 框架(JsonRpc、WebApi 等)共享同一套注册机制:
.ConfigureContainer(a =>
{
a.AddRpcStore(store =>
{
store.RegisterServer<MyMcpService>();
});
})
更多注册 RPC 服务的方法请参考:注册 Rpc 服务
7.2 服务生命周期
SingletonRpcServer:单例,所有请求共享同一个实例。TransientRpcServer:瞬态,每次请求创建新实例。ScopedRpcServer:区域,在 Scoped IOC 容器中按区域单例。
八、高级配置
8.1 自定义服务器信息
通过 McpServerOptions.ServerInfo 设置服务器名称和版本,该信息会在 initialize 握手时返回给客户端:
options.ServerOptions.ServerInfo = new McpImplementationInfo
{
Name = "MyMcpServer",
Version = "1.0.0"
};
8.2 设置使用说明
通过 McpServerOptions.Instructions 设置服务器的使用说明,该信息会在初始化响应中返回:
options.ServerOptions.Instructions = "这是一个演示服务器,提供加法计算和服务器信息查询功能。";
8.3 获取调用上下文
MCP 服务方法可以通过参数注入 IMcpCallContext 获取调用上下文,从而获取 MCP 请求 ID 等信息:
[McpTool]
[Description("带上下文的工具示例")]
public string ToolWithContext(IMcpCallContext callContext, string input)
{
var requestId = callContext.McpRequestId;
return $"请求 ID:{requestId},输入:{input}";
}
8.4 使用依赖注入
服务方法参数可以通过 [FromServices] 特性从 IOC 容器中注入依赖:
[McpTool]
[Description("使用依赖注入的工具")]
public string ToolWithDI([FromServices] ILog logger, string message)
{
logger.Info(message);
return "已记录日志";
}