springboot配置

maven配置

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.ai</groupId>
  4. <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
  5. <version>1.0.1</version>
  6. </dependency>
  7. </dependencies>

yaml配置

  1. spring:
  2. ai:
  3. mcp:
  4. server:
  5. stdio: false # 禁用stdio协议
  6. name: wbw-mcp-server # mcp-server名称
  7. sse-endpoint: /mcp # 启动sse协议,并指定端点路径为/sse
  8. enabled: true # 组件启用

访问 /mcp服务器时,报错如下:

  1. jakarta.servlet.ServletException: java.lang.NullPointerException: Cannot invoke "io.modelcontextprotocol.spec.McpServerSession$Factory.create(io.modelcontextprotocol.spec.McpServerTransport)" because "this.sessionFactory" is null
  2. at org.springframework.web.servlet.function.ErrorHandlingServerResponse.handleError(ErrorHandlingServerResponse.java:70) ~[spring-webmvc-6.2.10.jar:6.2.10]
  3. at org.springframework.web.servlet.function.AbstractServerResponse.writeTo(AbstractServerResponse.java:105) ~[spring-webmvc-6.2.10.jar:6.2.10]
  4. at org.springframework.web.servlet.function.support.HandlerFunctionAdapter.handle(HandlerFunctionAdapter.java:112) ~[spring-webmvc-6.2.10.jar:6.2.10]
  5. at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.2.10.jar:6.2.10]
  6. at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.2.10.jar:6.2.10]
  7. at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.10.jar:6.2.10]
  8. at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.2.10.jar:6.2.10]
  9. at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.44.jar:6.0]
  10. at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.2.10.jar:6.2.10]
  11. at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.44.jar:6.0]
  12. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  13. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  14. at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.44.jar:10.1.44]
  15. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  16. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  17. at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.2.10.jar:6.2.10]
  18. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.10.jar:6.2.10]
  19. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  20. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  21. at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.2.10.jar:6.2.10]
  22. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.10.jar:6.2.10]
  23. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  24. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  25. at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.2.10.jar:6.2.10]
  26. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.10.jar:6.2.10]
  27. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  28. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  29. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  30. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  31. at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  32. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:116) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  33. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  34. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  35. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  36. at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:398) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  37. at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  38. at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:903) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  39. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1769) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  40. at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  41. at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1189) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  42. at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:658) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  43. at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
  44. at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
  45. Caused by: java.lang.NullPointerException: Cannot invoke "io.modelcontextprotocol.spec.McpServerSession$Factory.create(io.modelcontextprotocol.spec.McpServerTransport)" because "this.sessionFactory" is null
  46. at io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider.lambda$handleSseConnection$6(WebMvcSseServerTransportProvider.java:266) ~[mcp-spring-webmvc-0.10.0.jar:0.10.0]
  47. at org.springframework.web.servlet.function.SseServerResponse.writeToInternal(SseServerResponse.java:95) ~[spring-webmvc-6.2.10.jar:6.2.10]
  48. at org.springframework.web.servlet.function.AbstractServerResponse.writeTo(AbstractServerResponse.java:101) ~[spring-webmvc-6.2.10.jar:6.2.10]
  49. ... 41 common frames omitted

原因

经过分析发现,主要是由于mcp自动装配的类:org.springframework.ai.mcp.server.autoconfigure.McpServerAutoConfiguration#mcpSyncServer没有初始化,在启动类打印mcpSyncServer是否懒加载,分析发现该bean时满足加载条件,但是不知道为啥就是类型时懒加载,导致没法加载
图片alt

  1. public static void main(String[] args) {
  2. ConfigurableApplicationContext context = SpringApplication.run(BoboServiceApplication.class, args);
  3. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  4. String[] beanNames = context.getBeanDefinitionNames();
  5. for (String beanName : beanNames) {
  6. BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
  7. if (beanName.contains("mcpSyncServer")) {
  8. System.out.println("Bean: " + beanName + " is lazy: " + beanDefinition.isLazyInit());
  9. }
  10. }
  11. }

发现提示时懒加载,导致初始化时没有加载
图片alt

解决办法

通过 BeanDefinitionRegistryPostProcessor 在运行时修改 Bean 定义,禁用懒加载:

  1. package com.bowen.service.config;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanDefinition;
  4. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  5. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  6. import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
  7. import org.springframework.context.annotation.Configuration;
  8. /**
  9. * 解决mcpSyncServer类首次启动时懒加载,导致报错了
  10. */
  11. @Configuration
  12. public class McpServerBeanDefinitionConfig implements BeanDefinitionRegistryPostProcessor {
  13. @Override
  14. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  15. // 检查是否存在 mcpSyncServer Bean 定义
  16. if (registry.containsBeanDefinition("mcpSyncServer")) {
  17. BeanDefinition beanDefinition = registry.getBeanDefinition("mcpSyncServer");
  18. // 禁用懒加载
  19. beanDefinition.setLazyInit(false);
  20. System.out.println("Disabled lazy initialization for mcpSyncServer");
  21. }
  22. }
  23. @Override
  24. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  25. // 不需要额外处理
  26. }
  27. }