博客详情页背景图

springboot2.x基于Solon搭建MCP服务,附带源码和jar包

基于springboot框架搭建mcp服务,使用solon集成springboot快速集成mcp

2025-12-21 · 后端

看了一下网上搭建MCP服务基于springboot2.x版本的,找了几个发现写的都有遗漏,这里记录一下自己的搭建过程

流程:
    1.基于solon框架集成springboot2.x版本,通过springboot启动solon服务
    2.基于solon服务实现MCP的搭建访问
    3.测试MCP服务访问,这里测试chatbox逻辑是通用的
注:
    1.为什么基于solon搭建,springboot2.x不支持官方的ai,如果新项目可以直接使用solon开发;或者使用springboot3.x版本,新项目可以直接参考web2mcp方式
    2.源码基于官方源码修改,添加个人注释,可以参考注释,整体比较简单的
    3.mcp为对应源码的mcpserver包下内容
    4.这里实现的是基于不影响之前开发的项目,可以通过远程调用方式访问
  1. springboot添加maven添加依赖
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-mcp</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-lib</artifactId>
</dependency>
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-web-servlet</artifactId>
</dependency>
  1. 修改启动类,添加必要的几个类
启动类HelloApp添加启动solon
@RestController
@SpringBootApplication
public class HelloApp {
    public static void main(String[] args) {
        if(Solon.app() != null) {
            return;
        }

        SpringApplication.run(HelloApp.class, args);
    }
}
配置类McpServerConfig复制即可
@Configuration
public class McpServerConfig {
    @Value("${server.servlet.context-path:}")
    private String contextPath;

    @Autowired
    private List<IMcpServerEndpoint> serverEndpoints;

    @PostConstruct
    public void start() {
        /**
         * Spring 注解支持
         * */

        ToolSchemaUtil.addBodyDetector(e -> e.isAnnotationPresent(RequestBody.class));
        ToolSchemaUtil.addParamResolver((e,t)->{
            RequestParam p1Anno = e.getAnnotation(RequestParam.class);

            if (p1Anno != null) { //这个注解因为没有描述字段,所以变量名一定要很语义
                Parameter p1 = (Parameter) e;
                String name = Utils.annoAlias(p1Anno.name(), p1.getName());
                return new ParamDesc(name, t.getGenericType(), p1Anno.required(), "");
            }

            return null;
        });
        System.setProperty("server.contextPath", contextPath);

        Solon.start(McpServerConfig.class, new String[]{}, app -> {
            app.enableScanning(false);
            app.filter(new McpServerAuth());
        });

        //实现了IMcpServerEndpoint接口,会自动注入到solon容器中
        springCom2Endpoint();
    }

    @PreDestroy
    public void stop() {
        if (Solon.app() != null) {
            //停止 solon(根据配置,可支持两段式安全停止)
            Solon.stopBlock(false, Solon.cfg().stopDelay());
        }
    }

    //Spring 组件转为端点
    protected void springCom2Endpoint() {
        //提取实现容器里 IMcpServerEndpoint 接口的 bean ,并注册为服务端点
        for (IMcpServerEndpoint serverEndpoint : serverEndpoints) {
            Class<?> serverEndpointClz = AopUtils.getTargetClass(serverEndpoint);
            McpServerEndpoint anno = AnnotationUtils.findAnnotation(serverEndpointClz, McpServerEndpoint.class);

            if (anno == null) {
                continue;
            }

            McpServerEndpointProvider serverEndpointProvider = McpServerEndpointProvider.builder()
                    .from(serverEndpointClz, anno)
                    .build();

            serverEndpointProvider.addTool(new MethodToolProvider(serverEndpointClz, serverEndpoint));
            serverEndpointProvider.addResource(new MethodResourceProvider(serverEndpointClz, serverEndpoint));
            serverEndpointProvider.addPrompt(new MethodPromptProvider(serverEndpointClz, serverEndpoint));

            serverEndpointProvider.postStart();
        }
    }

    //其他app可以通过http访问到部署到mcp服务
    @Bean
    public FilterRegistrationBean mcpServerFilter() {
        //通过 Servlet Filter 实现 http 能力对接
        FilterRegistrationBean<SolonServletFilter> filter = new FilterRegistrationBean<>();
        filter.setName("SolonFilter");
        filter.addUrlPatterns("/mcp/*");
        filter.setFilter(new SolonServletFilter());
        return filter;
    }
}
认证类McpServerAuth复制即可,有需要添加认证的可以添加
public class McpServerAuth implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        //如何鉴权“按需”设定(path 的过滤,与端点路径对应起来)
        if (ctx.pathNew().startsWith("/mcp/")
                && ctx.pathNew().endsWith("/message") == false) { //message 端点不需要签权
            String authStr = ctx.param("user"); //或者 ctx.header(...)
            if ("no".equals(authStr)) { //模拟 401 效果
                ctx.status(401);
                ctx.setHandled(true);
                return;
            }

            //业务检测
        }

        chain.doFilter(ctx);
    }
}
访问路径类ToolController需要实现IMcpServerEndpoint,在配置类中会注入到solon中,添加访问路径
@Service
@McpServerEndpoint(channel = McpChannel.STREAMABLE, mcpEndpoint = "/mcp/sse/demo1")
public class ToolController implements IMcpServerEndpoint {

    @ToolMapping(description = "查询天气预报, 返回地点和度数")
    public String getWeather(@Param(description = "城市位置") String location) {
        //todo  这里可以通过注入  使用远程调用的方式访问服务,直接返回object对象即可
        return "晴,14度";
    }
}
配置文件可以指定端口号 这里指定的是
server:
  servlet:
    encoding:
      force: true
      charset: UTF-8
      enabled: true
  port: 3011
  1. 启动项目,连接测试
项目启动后,可以通过http://localhost:3011//mcp/sse/demo1连接到部署到mcp服务器
启用mcp,测试提示词访问是否能直接调用即可

4.注意事项

1.导入到包需要查看是否是solon的,别导入错了
    import org.noear.solon.ai.annotation.PromptMapping;
    import org.noear.solon.ai.annotation.ResourceMapping;
    import org.noear.solon.ai.annotation.ToolMapping;
    import org.noear.solon.ai.chat.message.ChatMessage;
    import org.noear.solon.ai.mcp.McpChannel;
    import org.noear.solon.ai.mcp.server.IMcpServerEndpoint;
    import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint;
    import org.noear.solon.annotation.Param;
    import org.springframework.stereotype.Service;
2.开发阶段会多次重启mcp服务器,重启后在chatbox中mcp需要关闭再打开,重新建立连接,否则根据原有的会话id请求不通,后续可以采取缓存机制
夸克网盘下载 百度网盘下载
源码下载