本文档介绍了MCP(Model Context Protocol)架构,这是一种旨在简化和标准化数据访问的协议。MCP通过定义MCP Hosts、MCP Clients和MCP Servers等组件,实现了不同程序之间的数据交互。MCP Hosts是希望通过MCP访问数据的程序,MCP Clients维护与服务器的连接,而MCP Servers则提供特定的数据访问能力。这种架构支持本地数据源和远程服务,为开发者提供了更大的灵活性和可扩展性。文档还详细说明了如何在Spring AI框架下配置和使用MCP Server和Client,并提供了一个音乐推荐的示例,展示了如何通过MCP实现Tool的注册和调用。
🔑MCP(模型上下文协议)是一种架构,旨在为程序提供标准化的数据访问方式,它通过定义 Hosts、Clients 和 Servers 三个核心组件,简化数据交互流程。
⚙️ MCP Server 是一个轻量级程序,负责通过 MCP 提供特定的能力,它可以安全地访问本地数据源,并连接到互联网上的外部系统,如通过 APIs。
🎶 文档提供了一个音乐推荐的示例,展示了如何在 Spring AI 框架下配置和使用 MCP Server 和 Client,通过 `@Tool` 注解将推荐音乐的函数注册为工具,供 Client 调用。
🔗 为了使 Client 能够成功调用 Server 提供的 Tool,需要在 Client 端开启 `spring.ai.mcp.client.toolcallback.enabled = true` 配置,否则启动时会报错。
MCP架构
MCP中文文档

MCP Hosts: 如 Claude Desktop、IDE 或 AI 工具,希望通过 MCP 访问数据的程序MCP Clients: 维护与服务器一对一连接的协议客户端MCP Servers: 轻量级程序,通过标准的 Model Context Protocol 提供特定能力本地数据源: MCP 服务器可安全访问的计算机文件、数据库和服务远程服务: MCP 服务器可连接的互联网上的外部系统(如通过 APIs)
数据流
Prompt到达clientclient请求server,server选择合适的Function返回给client(可以根据需要,写自己的Function)client和model交互返回结果
Server
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.5</version> <relativePath/> </parent><properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>17</java.version> <spring-ai.version>1.0.0</spring-ai.version></properties><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-ollama</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>
# 端口server.port=8080# 不用但是要写,不然会报错spring.ai.openai.base-url=https://api.gptsapi.netspring.ai.openai.api-key=@{ollama.api-key}spring.ai.openai.chat.options.model=gpt-3.5-turbo# MCP 服务spring.ai.mcp.server.name=music-mcp-server#后续需要使用这个地址spring.ai.mcp.server.sse-message-endpoint= /mcp/recommendspring.ai.mcp.server.type = async
public interface RecommendService { String recommendInfo(); String recommendJpop();}@Servicepublic class RecommendServiceImpl implements RecommendService { @Tool(description = "推荐中国风音乐") @Override public String recommendInfo() { return "推荐音乐人河图,河山万里,图一个你!"; } @Tool(description = "推荐日本音乐") @Override public String recommendJpop() { return "JPOP领军人物米津玄师,你值得拥有!"; }}
@Configurationpublic class ToolCallbackProviderConfig { @Bean public ToolCallbackProvider gzhRecommendTools(RecommendService recommendService) { return MethodToolCallbackProvider.builder().toolObjects(recommendService).build(); }}
Client
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.5</version> <relativePath/> </parent><properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>17</java.version> <spring-ai.version>1.0.0</spring-ai.version></properties><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-ollama</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-autoconfigure-mcp-client</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>
spring.application.name=mcp-clientspring.ai.openai.api-key=your_openai_api_key_herespring.ai.ollama.base-url=http://localhost:11434spring.ai.ollama.chat.model=qwen3spring.mvc.async.request-timeout=0spring.codec.charset=UTF-8spring.codec.max-in-memory-size=1MBserver.port=8081spring.ai.mcp.client.name=mcp-clientspring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080spring.ai.mcp.client.toolcallback.enabled = true
@RestControllerpublic class McpController { @Autowired private OllamaChatModel ollamaChatModel; @Autowired private ToolCallbackProvider toolCallbackProvider; @GetMapping("/mcp/generate") public String generate(@RequestParam(value = "message", defaultValue = "推荐一首歌") String message) { ChatClient chatClient = ChatClient.builder(ollamaChatModel) .defaultToolCallbacks(toolCallbackProvider.getToolCallbacks()) .build(); ChatClient.CallResponseSpec call = chatClient.prompt(message).call(); return call.content(); }}
测试