在这里插入图片描述

引言

在人工智能应用快速发展的今天,如何让 AI 助手安全、高效地访问外部工具和数据源成为架构设计的关键挑战。Anthropic 推出的 MCP(Model Context Protocol,模型上下文协议) 提供了一种标准化的解决方案。作为 Java 生态系统的领导者,Spring 社区通过 Spring AI 为开发者提供了便捷的 MCP 支持,使得在 Spring Boot 应用中构建 MCP 服务变得前所未有的简单。

本文将深入探讨如何利用 Spring Boot 和 Spring AI 构建完整的 MCP 服务,涵盖从基础概念到生产级实现的完整技术路径。

MCP 协议核心概念

什么是 MCP

MCP(Model Context Protocol)是一种开放标准协议,旨在定义 AI 助手与外部工具、数据源之间的标准化通信方式。它由 Anthropic 创建,最初用于增强 Claude 的能力,如今已发展成为跨平台、跨语言的通用协议。

MCP 的核心价值在于解决了 AI 应用与外部系统集成时的碎片化问题。在 MCP 出现之前,每个 AI 应用需要为不同的数据源和工具实现独立的集成代码,导致大量重复工作。MCP 通过提供统一的接口规范,让 AI 应用可以透明地调用任何支持 MCP 的外部服务。

MCP 架构概览

MCP 采用经典的客户端-服务器架构,主要包含以下核心组件:

MCP 主机(Host):这是用户直接交互的 AI 应用程序,如 Claude Desktop、Cursor 或自定义聊天应用。主机负责协调用户请求、调用工具并生成响应。

MCP 客户端(Client):位于主机内部,负责与一个或多个 MCP 服务器建立和维护连接。客户端处理协议层面的通信细节,包括请求序列化、响应解析等。

MCP 服务器(Server):这是我们使用 Spring Boot 构建的核心组件。服务器暴露工具(Tools)、资源(Resources)和提示(Prompts),供客户端调用。服务器通常与实际的数据源或服务(数据库、文件系统、API 等)进行交互。

传输层(Transport):MCP 支持多种传输方式,包括标准输入输出(STDIO)和 Server-Sent Events(SSE)。STDIO 适合本地命令行集成,SSE 则支持基于 HTTP 的远程通信。

核心原语

MCP 定义了三种主要的原语来暴露功能:

工具(Tools):可执行的函数或方法,这是 MCP 最常用的原语。工具可以执行数据库查询、调用外部 API、执行计算等任何业务逻辑。每个工具都有明确定义的输入模式和输出格式。

资源(Resources):类似于传统 REST API 中的资源概念,资源提供数据访问能力。客户端可以列出可用资源、读取资源内容。资源可以是文件、数据库查询结果或任何动态生成的数据。

提示(Prompts):预定义的提示模板,可以包含动态参数。提示帮助 AI 更好地利用特定领域的上下文信息。

Spring AI MCP 生态概览

Spring AI 简介

Spring AI 是 Spring 生态系统为人工智能应用提供的集成框架。它简化了与各种 AI 模型提供商的交互,包括 OpenAI、Anthropic、Azure OpenAI、Hugging Face 等。Spring AI 提供了统一的 API 抽象,让开发者可以使用相同的代码模式接入不同的 AI 提供商。

MCP 支持的演进

Spring AI 从 1.0.0 版本开始正式支持 MCP 协议。随着版本迭代,MCP 支持不断完善。最新的 Spring AI 1.1.0-M2 版本基于 MCP Java SDK v0.13.1 构建,支持 MCP 协议版本 2025-06-18,并提供了多项关键改进:

  • 改进的工具名称前缀生成和重复处理
  • AOT(Ahead-of-Time)编译支持
  • 改进的 JSON 序列化能力
  • 更完善的配置属性体系

可用的 Spring AI MCP 组件

Spring AI 提供了两组关键的 Starter 组件:

MCP Server 端

  • spring-ai-starter-mcp-server-webmvc:基于 Spring MVC 的 MCP 服务器,支持同步 HTTP 通信
  • spring-ai-starter-mcp-server-webflux:基于 Spring WebFlux 的 MCP 服务器,支持 SSE 和响应式编程

MCP Client 端

  • spring-ai-starter-mcp-client:标准 MCP 客户端
  • spring-ai-starter-mcp-client-sse:支持 SSE 的 MCP 客户端

开发者可以根据实际需求选择合适的组件。对于大多数应用场景,WebFlux 版本提供了更好的性能和实时能力。

项目初始化与依赖配置

环境要求

在开始实现之前,确保开发环境满足以下要求:

  • Java 17 或更高版本(推荐 Java 21)
  • Maven 3.8+ 或 Gradle 7+
  • Spring Boot 3.2+(推荐 3.4.x)

创建 Spring Boot 项目

使用 Spring Initializr 快速创建项目基础结构。在添加依赖时,选择以下模块:

  • Spring Web(构建 REST API)
  • Model Context Protocol Server(MCP 服务器支持)

Maven 依赖配置

pom.xml 中添加必要的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.2</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>mcp-server-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mcp-server-demo</name>
    <description>Spring Boot MCP Server Demo</description>
    
    <properties>
        <java.version>21</java.version>
        <spring-ai.version>1.0.0</spring-ai.version>
    </properties>
    
    <dependencies>
        <!-- Spring Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring AI MCP Server -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        
        <!-- Spring AI OpenAI (如果需要调用外部 AI) -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-openai</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        
        <!-- Lombok -->
        <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>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

配置文件

application.yml 中配置 MCP 服务器的基本参数:

server:
  port: 8080

spring:
  ai:
    mcp:
      server:
        name: "conference-mcp-server"
        version: "1.0.0"
        type: sync
        stdio: false
        
# 日志配置
logging:
  level:
    org.springframework.ai: DEBUG
    io.modelcontextprotocol: DEBUG

核心实现:构建 MCP 工具服务

定义业务领域模型

首先,我们需要定义业务领域模型。以一个会议管理系统为例,我们创建实体类来表示会议和演讲者信息:

package com.example.mcpdemo.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Session {
    private String id;
    private String title;
    private String speaker;
    private String description;
    private String day;
    private String time;
    private String room;
    private String track;
}

创建服务层

接下来创建服务类,实现业务逻辑:

package com.example.mcpdemo.service;

import com.example.mcpdemo.model.Session;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ConferenceService {
    
    private final List<Session> sessions;
    
    public ConferenceService() {
        this.sessions = initializeSessions();
    }
    
    private List<Session> initializeSessions() {
        List<Session> list = new ArrayList<>();
        list.add(new Session("1", "Opening Keynote: The Future of AI", 
            "Dr. Sarah Chen", "Exploring AI trends", "Thursday", "09:00", 
            "Main Hall", "Keynote"));
        list.add(new Session("2", "Building MCP Servers with Spring AI", 
            "John Doe", "Hands-on guide", "Thursday", "10:30", 
            "Room A", "Development"));
        list.add(new Session("3", "Cloud Native Development", 
            "Jane Smith", "K8s best practices", "Thursday", "11:30", 
            "Room B", "DevOps"));
        list.add(new Session("4", "Machine Learning in Production", 
            "Mike Johnson", "MLOps strategies", "Thursday", "14:00", 
            "Room A", "ML/AI"));
        list.add(new Session("5", "Security Best Practices", 
            "Alice Brown", "AppSec overview", "Friday", "09:30", 
            "Main Hall", "Security"));
        list.add(new Session("6", "Closing Keynote", 
            "Dr. Sarah Chen", "Wrap up", "Friday", "16:00", 
            "Main Hall", "Keynote"));
        return list;
    }
    
    public List<Session> getAllSessions() {
        return new ArrayList<>(sessions);
    }
    
    public List<Session> getSessionsByDay(String day) {
        return sessions.stream()
            .filter(s -> s.getDay().equalsIgnoreCase(day))
            .collect(Collectors.toList());
    }
    
    public List<Session> getSessionsByTrack(String track) {
        return sessions.stream()
            .filter(s -> s.getTrack().equalsIgnoreCase(track))
            .collect(Collectors.toList());
    }
    
    public Session getSessionById(String id) {
        return sessions.stream()
            .filter(s -> s.getId().equals(id))
            .findFirst()
            .orElse(null);
    }
    
    public List<Session> searchSessions(String keyword) {
        String lowerKeyword = keyword.toLowerCase();
        return sessions.stream()
            .filter(s -> s.getTitle().toLowerCase().contains(lowerKeyword) ||
                        s.getDescription().toLowerCase().contains(lowerKeyword) ||
                        s.getSpeaker().toLowerCase().contains(lowerKeyword))
            .collect(Collectors.toList());
    }
    
    public long countSessionsByDay(String day) {
        return sessions.stream()
            .filter(s -> s.getDay().equalsIgnoreCase(day))
            .count();
    }
}

使用 @Tool 注解暴露服务方法

这是实现 MCP 服务的核心步骤。Spring AI 允许开发者使用 @Tool 注解直接标记服务方法,无需编写繁琐的协议处理代码:

package com.example.mcpdemo.tools;

import com.example.mcpdemo.model.Session;
import com.example.mcpdemo.service.ConferenceService;
import org.springframework.ai.mcp.annotation.Tool;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class ConferenceTools {
    
    private final ConferenceService conferenceService;
    
    public ConferenceTools(ConferenceService conferenceService) {
        this.conferenceService = conferenceService;
    }
    
    @Tool(name = "get-all-sessions", description = "获取所有会议演讲信息")
    public List<Session> getAllSessions() {
        return conferenceService.getAllSessions();
    }
    
    @Tool(name = "get-sessions-by-day", 
          description = "根据日期获取会议演讲列表,例如:Thursday 或 Friday")
    public List<Session> getSessionsByDay(String day) {
        return conferenceService.getSessionsByDay(day);
    }
    
    @Tool(name = "get-sessions-by-track", 
          description = "根据主题获取会议演讲列表,如:Development, DevOps, ML/AI, Security")
    public List<Session> getSessionsByTrack(String track) {
        return conferenceService.getSessionsByTrack(track);
    }
    
    @Tool(name = "get-session-by-id", 
          description = "根据演讲ID获取详细信息")
    public Session getSessionById(String id) {
        return conferenceService.getSessionById(id);
    }
    
    @Tool(name = "search-sessions", 
          description = "搜索会议演讲,通过关键词匹配标题、描述或演讲者")
    public List<Session> searchSessions(String keyword) {
        return conferenceService.searchSessions(keyword);
    }
    
    @Tool(name = "count-sessions-by-day", 
          description = "统计某一天的演讲数量")
    public long countSessionsByDay(String day) {
        return conferenceService.countSessionsByDay(day);
    }
}

工具方法命名与描述规范

在定义 @Tool 方法时,需要注意以下规范:

工具名称(name):必须是唯一的,通常使用 kebab-case 命名风格。Spring AI 会自动处理名称冲突,添加前缀或后缀以确保唯一性。

工具描述(description):这是 AI 模型理解工具用途的关键依据。描述应该清晰、准确,包含:

  • 工具的主要功能
  • 参数的含义和预期格式
  • 可能的返回值类型

良好的描述能够帮助 AI 正确调用工具,提高整体系统的准确率。

注册 MCP 服务器

在 Spring AI 中,MCP 服务器的注册通常是自动的。Spring 会扫描带有 @Tool 注解的方法,并自动创建对应的工具定义。但我们需要创建配置类来确保组件正确加载:

package com.example.mcpdemo.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ai.mcp.tool.MethodToolCallbackProvider;

@SpringBootApplication
public class McpServerApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(McpServerApplication.class, args);
    }
    
    @Bean
    public MethodToolCallbackProvider methodToolCallbackProvider() {
        return MethodToolCallbackProvider.builder().build();
    }
}

高级:自定义 MCP 服务器配置

对于更复杂的需求,可以手动配置 MCP 服务器参数:

package com.example.mcpdemo.config;

import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.spec.McpServerRunner;
import io.modelcontextprotocol.spec.McpSchema;
import org.springframework.ai.mcp.SyncMcpServerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class McpServerConfiguration {
    
    @Bean
    public SyncMcpServerAdapter mcpServerAdapter() {
        return new SyncMcpServerAdapter(
            McpServer.builder()
                .serverInfo(
                    McpSchema.ServerInfo.builder()
                        .name("my-custom-mcp-server")
                        .version("1.0.0")
                        .build()
                )
                .build()
        );
    }
}

暴露资源与提示

暴露数据资源

MCP 的资源原语允许服务器暴露可供客户端读取的数据。在 Spring AI 中,可以通过实现特定接口或使用配置来暴露资源:

package com.example.mcpdemo.resources;

import org.springframework.ai.mcp.resource.Resource;
import org.springframework.ai.mcp.resource.ResourceResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class ResourceConfiguration {
    
    @Bean
    public ResourceResolver resourceResolver() {
        return new ResourceResolver() {
            @Override
            public List<String> listResources() {
                return List.of(
                    "conference://sessions",
                    "conference://speakers"
                );
            }
            
            @Override
            public Resource getResource(String uri) {
                if (uri.equals("conference://sessions")) {
                    return new Resource() {
                        @Override
                        public String getUri() {
                            return "conference://sessions";
                        }
                        
                        @Override
                        public String getName() {
                            return "Conference Sessions";
                        }
                        
                        @Override
                        public String getDescription() {
                            return "List of all conference sessions";
                        }
                        
                        @Override
                        public String getMimeType() {
                            return "application/json";
                        }
                        
                        @Override
                        public byte[] read() {
                            return "[]".getBytes();
                        }
                    };
                }
                return null;
            }
        };
    }
}

传输协议配置

STDIO 传输模式

STDIO 传输适合本地集成场景,例如与 Claude Desktop 配合使用:

spring:
  ai:
    mcp:
      server:
        stdio: true
        type: sync

启用 STDIO 后,应用不会启动 Web 服务器,而是通过标准输入输出进行通信。

SSE 传输模式

SSE(Server-Sent Events)适合需要远程访问的场景:

spring:
  ai:
    mcp:
      server:
        stdio: false
        type: sync

SSE 模式下,MCP 服务器会在以下端点暴露服务:

  • POST /mcp/message:处理 MCP 消息请求
  • GET /mcp/sse:建立 SSE 连接用于实时推送

WebFlux 响应式支持

对于高并发场景,可以使用 WebFlux 版本获得更好的性能:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>

WebFlux 版本支持完整的响应式编程模型,适合构建实时性要求较高的应用。

测试与调试

本地测试 MCP 服务器

使用 MCP Inspector 工具可以方便地测试 MCP 服务器:

# 安装 MCP Inspector
npm install -g @modelcontextprotocol/inspector

# 启动 Inspector 并连接本地服务器
mcp-inspector stdio -- java -jar target/mcp-server-demo-0.0.1-SNAPSHOT.jar

Inspector 提供了图形界面,可以列出服务器提供的所有工具,查看工具定义,并执行测试调用。

与 Claude Desktop 集成

将 MCP 服务器配置到 Claude Desktop:

  1. 打开 Claude Desktop 配置目录:

    • macOS:~/Library/Application Support/Claude/
    • Windows:%APPDATA%/Claude/
  2. 编辑 claude_desktop_config.json

{
  "mcpServers": {
    "conference-server": {
      "command": "java",
      "args": [
        "-jar",
        "/path/to/mcp-server-demo-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}
  1. 重启 Claude Desktop

单元测试

创建针对 MCP 工具的单元测试:

package com.example.mcpdemo;

import com.example.mcpdemo.tools.ConferenceTools;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ConferenceToolsTest {
    
    @Autowired
    private ConferenceTools conferenceTools;
    
    @Test
    void testGetAllSessions() {
        var sessions = conferenceTools.getAllSessions();
        assertNotNull(sessions);
        assertFalse(sessions.isEmpty());
    }
    
    @Test
    void testGetSessionsByDay() {
        var thursdaySessions = conferenceTools.getSessionsByDay("Thursday");
        assertTrue(thursdaySessions.size() > 0);
        
        var fridaySessions = conferenceTools.getSessionsByDay("Friday");
        assertTrue(fridaySessions.size() > 0);
    }
    
    @Test
    void testSearchSessions() {
        var results = conferenceTools.searchSessions("AI");
        assertFalse(results.isEmpty());
    }
    
    @Test
    void testCountSessionsByDay() {
        var count = conferenceTools.countSessionsByDay("Thursday");
        assertTrue(count > 0);
    }
}

MCP 客户端实现

除了构建 MCP 服务器,Spring AI 也支持实现 MCP 客户端来消费外部 MCP 服务。

配置 MCP 客户端

spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            weather-server:
              url: http://localhost:8081
            file-server:
              url: http://localhost:8082

在代码中使用 MCP 工具

@Service
public class ChatService {
    
    private final ChatClient chatClient;
    
    public ChatService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    
    public String chat(String userMessage) {
        return chatClient.prompt()
            .user(userMessage)
            .call()
            .content();
    }
}

典型应用场景

企业内部知识库

企业可以使用 Spring Boot 构建 MCP 服务,将内部文档、数据库、API 等资源暴露给 AI 助手。员工可以通过自然语言查询技术文档、检索产品信息、执行常见操作。

业务流程自动化

将企业业务流程封装为 MCP 工具,AI 助手可以代替用户执行复杂的多步骤操作,如订单处理、审批流程触发、数据同步等。

数据分析平台

构建支持 MCP 的数据分析服务,AI 可以调用数据查询、报表生成、数据可视化等工具,帮助用户快速获取业务洞察。

多系统集成

通过 MCP 协议连接多个遗留系统或第三方服务,AI 充当统一的数据交换层,简化系统间集成复杂度。

优势分析

Spring 生态系统集成

使用 Spring Boot 构建 MCP 服务的最大优势在于可以充分利用 Spring 生态系统的丰富特性:

  • 依赖注入和自动配置简化了组件管理
  • Spring Data 支持轻松连接各类数据库
  • Spring Security 提供完善的安全保障
  • 成熟的测试框架确保代码质量

声明式工具定义

通过 @Tool 注解,开发者可以用最少的代码暴露复杂的业务功能。Spring AI 负责处理协议解析、参数验证、结果序列化等繁琐工作。

灵活的传输支持

Spring AI MCP 支持 STDIO、SSE 和 WebFlux 三种传输模式,可以根据实际需求选择最合适的方案。本地集成使用 STDIO,远程服务使用 SSE,高并发场景使用 WebFlux。

生产级稳定性

Spring AI 基于 MCP Java SDK 构建,该 SDK 由 Anthropic 官方维护和更新,确保了与最新 MCP 协议规范的兼容性。Spring 的发布周期也保证了及时的安全更新和 bug 修复。

注意事项与最佳实践

安全性考虑

在生产环境中部署 MCP 服务时,需要关注以下安全要点:

认证与授权:MCP 协议本身不包含认证机制,需要在传输层实现。可以考虑使用 API Key、JWT 或 OAuth2 进行保护。

输入验证:对工具参数进行严格验证,防止注入攻击。

日志审计:记录工具调用日志,便于问题排查和合规审计。

限流保护:防止恶意请求对服务造成压力。

性能优化

模型缓存:首次加载模型可能耗时较长,确保模型正确缓存。

连接池:对于需要调用外部 API 的工具,使用连接池提高效率。

异步处理:对于耗时操作,考虑使用异步处理模式。

监控与可观测性

集成 Spring Boot Actuator 提供健康检查、指标监控等能力:

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,info

总结

MCP 为 AI 应用与外部系统的集成提供了标准化的解决方案,而 Spring Boot + Spring AI 的组合使得构建 MCP 服务变得简洁高效。开发者可以专注于业务逻辑的实现,将协议处理的复杂性交给框架处理。

通过本文介绍的技术,开发者可以快速构建功能完整的 MCP 服务器,将企业数据和服务能力无缝暴露给 AI 助手。随着 AI 应用的持续发展,掌握 MCP 服务开发将成为 Java 工程师的重要技能。

🎁 福利时间

如果你正在备战面试或者想要学习其他知识,给大家推荐一个宝藏知识库,作者整理了一些列 Java 程序员需要掌握的核心知识,有需要的自取不谢。

知识库地址:https://farerboy.com/


Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐