1.ModelContextProtocol SDK支持

ModelContextProtocol SDK,由spring团队开发,基于spring-core和spring-webmvc进行开发。提供了mcp-server,mcp-client的相关实现。

最初,Anthropic 发布 MCP(模型上下文协议)规范时,官方只提供了 TypeScript / Node.js 和 Python 的 SDK。当时,VMware 旗下的 Spring AI 团队发现 MCP 规范设计得非常精妙,于是在开发 Spring AI 的过程中,顺手用 Java 纯手写实现了一套高性能、分层清晰的 Java/Kotlin 版 MCP SDK。由于 Spring AI 团队写的这套 SDK 架构设计得极其优秀(完美融合了同步、以及基于 Project Reactor 的非阻塞异步/响应式流),Anthropic 官方看后非常认可。在 2025 年 1 月,Anthropic 官方与 Spring 团队联合宣布: 由 Spring AI 团队开发的 Java/Kotlin SDK,正式被收编为 MCP 协议全球官方指定的 Java SDK! 目前,Spring AI 团队已经作为模型上下文协议组织的组成部分,在 GitHub 的官方组织(modelcontextprotocol/java-sdk)下直接维护这个底层 SDK。

目前市面上的Java的AI框架,包括:SpringAI、SpringAI Alibaba、AgentScope、Embabel等,底层的MCP实现,都使用了ModelContextProtocol SDK。

2.Mcp-Server实现

2.1 原生ModelContextProtocol SDK

MCP-Server,有异步和同步两个版本:io.modelcontextprotocol.server.McpServer/io.modelcontextprotocol.server.McpAsyncServer,两者的实现逻辑基本一致。

  • MCP-Server内部会维护所有的tools/resources/resourceTemplates/prompts对应的requestHandlers,通过构造器的方式传进来。

内部都通过io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider(或者是Stream模式的io.modelcontextprotocol.spec.McpStreamableServerTransportProvider)进行请求的处理。

  • 支持各种JSONRPC请求的实现,比如tools/list、tools/call、resources/list、resources/read。
  • 通过SessionFactory管理所有的会话,SessionFactory在创建Session时,会将MCP-Server内部的requestHandlers等信息全部传递过去,以支持具体的JSONRPC请求的处理。

最终不管是SSE/STREAM,ServerTransportProvider都会暴露一个RouterFunction,方便方便应用程序接入到Spring应用当中;STDIO模式不需要暴露RouterFunction。

请求的处理流程:

  • 1.通过/sse地址(sseEndpoint),去生成当前客户端建立SSE的url,服务端通过endpoint字段去指定当前客户端的链接地址(完整url,路径+sessionId)。endPoint字段是由baseUrl+messageEndpoint拼接得到。
  • 2.客户端通过服务端(baseUrl+)messageEndpoint地址,携带上sessionId,去发起会话。
  • 3.服务端通过io.modelcontextprotocol.spec.McpSchema#deserializeJsonRpcMessage去解析客户端发起的入参信息,并处理请求。
    • 服务端解析使用的是对应的JsonMapper(io.modelcontextprotocol.json.McpJsonMapper),McpJsonMapper可能由Jackson2和Jackson3对应的ObjectMapper实现;在McpJsonInternal中通过SPI发现,如果都有的话,那么按照顺序随机取一个。
    • 报文格式可能是JSONRPCRequest/JSONRPCNotification/JSONRPCResponse,是标准的JSONRPC协议。
    • 处理工具调用的RequestHander是io.modelcontextprotocol.server.McpAsyncServer#toolsCallRequestHandler,它会拿到McpAsyncServer中已经注册的Tool进行处理。

2.2 SpringAI整合ModelContextProtocol

jar:org.springframework.ai:spring-ai-autoconfigure-mcp-server-common,在引入了这个Jar之后,就自动拥有了以STDIO的方式去进行MCP Server的暴露的能力。

代码位置:org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration。

	@Bean
	@ConditionalOnMissingBean
	public McpServerTransportProviderBase stdioServerTransport(
			@Qualifier("mcpServerObjectMapper") ObjectMapper mcpServerObjectMapper) {
		return new StdioServerTransportProvider(new JacksonMcpJsonMapper(mcpServerObjectMapper));
	}

    	@Bean
	@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
			matchIfMissing = true)
	public McpSyncServer mcpSyncServer(McpServerTransportProviderBase transportProvider,
			McpSchema.ServerCapabilities.Builder capabilitiesBuilder, McpServerProperties serverProperties,
			McpServerChangeNotificationProperties changeNotificationProperties,
			ObjectProvider<List<SyncToolSpecification>> tools,
			ObjectProvider<List<SyncResourceSpecification>> resources,
			ObjectProvider<List<SyncResourceTemplateSpecification>> resourceTemplates,
			ObjectProvider<List<SyncPromptSpecification>> prompts,
			ObjectProvider<List<SyncCompletionSpecification>> completions,
			ObjectProvider<BiConsumer<McpSyncServerExchange, List<McpSchema.Root>>> rootsChangeConsumers,
			Environment environment) {

   	@Bean
	@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
	public McpAsyncServer mcpAsyncServer(McpServerTransportProviderBase transportProvider,
			McpSchema.ServerCapabilities.Builder capabilitiesBuilder, McpServerProperties serverProperties,
			McpServerChangeNotificationProperties changeNotificationProperties,
			ObjectProvider<List<AsyncToolSpecification>> tools,
			ObjectProvider<List<AsyncResourceSpecification>> resources,
			ObjectProvider<List<AsyncResourceTemplateSpecification>> resourceTemplates,
			McpAsyncServer<List<AsyncPromptSpecification>> prompts,
			ObjectProvider<List<AsyncCompletionSpecification>> completions,
			ObjectProvider<BiConsumer<McpAsyncServerExchange, List<McpSchema.Root>>> rootsChangeConsumer) {

会自动注册一个基于STDIO的StdioServerTransportProvider实现,并注册一个McpSyncServer/McpAsyncServer。

如果想要基于SSE/STREAM的方式去暴露MCP-Server,那么需要引入"spring-ai-autoconfigure-mcp-server-webmvc"这个jar。

2.3 SpringAI整合原生ModelContextProtocol

代码位置:org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration。

以ASYNC模式为例:org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration#asyncTools。

SpringAI其实是以ToolCallback作为MCP的工具实现,这里会注入所有的ToolCallback和ToolCallbackProvider,通过org.springframework.ai.mcp.McpToolUtils#toAsyncToolSpecification(org.springframework.ai.tool.ToolCallback, org.springframework.util.MimeType)将ToolCallback转换为MCP中的AsyncToolSpecification。

	@Bean
	@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
	public List<McpServerFeatures.AsyncToolSpecification> asyncTools(ObjectProvider<List<ToolCallback>> toolCalls,
			List<ToolCallback> toolCallbacksList, ObjectProvider<List<ToolCallbackProvider>> tcbProviderList,
			ObjectProvider<ToolCallbackProvider> tcbProviders, McpServerProperties serverProperties) {

		List<ToolCallback> tools = this.aggregateToolCallbacks(toolCalls, toolCallbacksList, tcbProviderList,
				tcbProviders);

		return this.toAsyncToolSpecification(tools, serverProperties);
	}

2.4 SpringComunity中的@McpTool等注解的实现

代码位置:org.springframework.ai.mcp.server.common.autoconfigure.annotations.McpServerSpecificationFactoryAutoConfiguration.SyncServerSpecificationConfiguration#toolSpecs。

也是将所有Bean中,所有标注@McpTool注解的方法去转换成为MCP中的AsyncToolSpecification。

		@Bean
		public List<McpServerFeatures.SyncToolSpecification> toolSpecs(
				ServerMcpAnnotatedBeans beansWithMcpMethodAnnotations) {
			List<Object> beansByAnnotation = beansWithMcpMethodAnnotations.getBeansByAnnotation(McpTool.class);
			return SyncMcpAnnotationProviders.toolSpecifications(beansByAnnotation);
		}