mcp - 服务端点构建方式与内容变更
支持 Mcp Server 多端点,是 solon-ai-mcp 的重要特色。其中 McpServerEndpointProvider(Mcp 服务端点提供者),是提供 Mcp Server 端点服务的实体。对应的配置属性实体为 McpServerProperties
配置属性 McpServerProperties:
属性 | 默认值 | 说明 |
---|---|---|
name | Solon-Ai-Mcp-Server | 服务名称 |
version | 1.0.0 | 服务端版本号 |
channel | McpChannel.SSE | 通讯方式(或通道) |
sseEndpoint | /mcp/sse | sse 端点(路径) |
heartbeatInterval | 30s | 服务器SSE心跳间隔(空表示不启用) |
为什么要支持多端点?
- 当有很多工具(或资源,或提示语)时,可以按业务分组。
- 比如,可以提供教育类的 mcp 服务,也可以提供金融类的 mcp 服务。
服务端开发时会涉及注解:
注解 | 说明 |
---|---|
@McpServerEndpoint | 标记当前类为一个 mcp 服务端点(和普通组件一样,比如:注入) |
@ToolMapping | 标记这个方法是一个工具映射。其中 description 属性是给大模型用的提示词,大模型会根据自己的理解调用这个工具,所以这个描述很重要。 |
@ResourceMapping | 标记这个方法是一个资源映射 |
@PromptMapping | 标记这个方法是一个提示语映射 |
@Param | 申明调用时需要传什么参数。其中 description 属性是给大模型用的提示词。 |
@Produces | 申明输出的内容类型,可配合 @ToolMapping 、@ResourceMapping 使用。如果是 josn 类型,则会进行 json 格式化(默认是转为字符串)。(v3.3.1 后支持) |
McpServerEndpointProvider 主要方法:
方法 | 说明 |
---|---|
postStart() | 确认启动 |
stop() | 停止(之后不能再用了,除非重启服务) |
pause()->bool | 暂停(主要用于测试),之后可以再恢复 |
resume()->bool | 恢复(主要用于测试) |
addTool(functionTool) | 添加工具申明 |
addTool(toolProvider) | 添加一批工具申明(ToolProvider) |
removeTool(toolName) | 移除工具申明(更新等于:移除+添加) |
removeTool(toolProvider) | 移除一批工具申明 |
getTools() | 获取所有工具申明 |
addResource(functionResource) | 添加资源申明 |
addResource(resourceProvider) | 添加一批资源申明(ResourceProvider) |
removeResource(resourceUri) | 移除资源申明(更新等于:移除+添加) |
removeResource(resourceProvider) | 移除一批资源申明 |
getResources() | 获取所有资源申明 |
addPrompt(functionPrompt) | 添加提示语申明 |
addPrompt(promptProvider) | 添加一批提示语申明(PromptProvider) |
removePrompt(promptName) | 移除提示语申明(更新等于:移除+添加) |
removePrompt(promptProvider) | 移除一批提示语申明 |
getPrompts() | 获取所提示语申明 |
1、使用注解构建服务端点
跟 mvc 开发差不多,非常简单(支持多个端点,即多个路径)。框架会把 @McpServerEndpoint
类自动转换为 McpServerEndpointProvider 并注册到容器(后续可以修改工具集)。
@McpServerEndpoint(name="mcp-case1", sseEndpoint = "/case1/sse")
public class McpServerTool {
@ToolMapping(description = "查询天气预报")
public String getWeather(@Param(description = "城市位置") String location) {
return "晴,14度";
}
}
//注入其它组件,配合使用
@McpServerEndpoint(name="mcp-case2", sseEndpoint = "/case2/sse")
public class McpServerTool {
@Inject
WeatherDao weatherDao;
@ToolMapping(description = "查询天气预报")
public String getWeather(@Param(description = "城市位置") String location) {
return weatherDao.query(location);
}
}
//做断线重连测试(v3.2.1 后支持)
@McpServerEndpoint(name="mcp-case3", sseEndpoint = "/case3/sse")
public class McpServerTool {
@ToolMapping(description = "查询天气预报")
public String getWeather(@Param(description = "城市位置") String location) {
return "晴,14度";
}
//注入当前工具对应的端点提供者
@Inject("mcp-case1")
private McpServerEndpointProvider serverEndpointProvider;
//30秒为间隔(暂停或恢复)//或者用 web 控制
@Scheduled(fixedRate = 30_000)
public void pauseOrResume() {
if (serverEndpointProvider.pause() == false) {
//如果暂停失败,说明之前已经暂停
serverEndpointProvider.resume();
}
}
}
2、使用代码构建服务端点
这个方案更自由,可以动态构建工具集。也可以在其它框架环境集成(spring、jfinal、vert.x 等...)
public class McpServerTool {
@ToolMapping(description = "查询天气预报")
public String getWeather(@Param(description = "城市位置") String location) {
return "晴,14度";
}
}
@Configuration
public class McpServerConfig {
@Bean("mcp-case4")
public McpServerEndpointProvider serverEndpoint() {
McpServerEndpointProvider serverEndpoint = McpServerEndpointProvider.builder()
.name("mcp-case4")
.sseEndpoint("/case4/sse")
.build();
serverEndpoint.addTool(new MethodToolProvider(new McpServerTool()));
return serverEndpoint;
}
}
其实还可以通过配置构建,但不如现有的两种方便。
3、服务端点的工具变更(添加或移除)
使用 web 控制器(或者定时任务,或者消息事件),动态添加工具和移除工具。如果是同名更新,需要先移除旧的,再添加新的。变更后,会自动同步到客户端。
@Controller
public class ToolController {
@Inject("mcp-case1")
McpServerEndpointProvider serverEndpointProvider;
@Mapping("/tool/add")
public void add(){
serverEndpointProvider.addTool(new FunctionToolDesc("hello").doHandle(map->{
return "hello world!";
}));
}
@Mapping("/tool/remove")
public void remove(){
serverEndpointProvider.removeTool("hello"); //移除后,会自动通知给客户端
}
}
4、McpServerEndpointProvider 的其它接口参考
接口 | 说明 | 备注 |
---|---|---|
getName() | 获取端点名字 | |
getSseEndpoint() | 获取服务内的 SSE 端点 | |
getTransport() | 获取传输提供者 | 主要内部使用 |
McpServerEndpointProvider.builder() | 实例化构建器 |