又一個AI大模型項目完結:基于Spring AI快速搭建MCP服務加入LLM,完整源碼已提交!
在人工智能技術飛速發展的今天,大語言模型正在重塑我們與軟件系統的交互方式。然而,這些強大的模型往往被困在"信息孤島"中——它們擁有驚人的推理能力,卻無法直接訪問企業數據、業務系統或實時信息。這正是 Model Context Protocol (MCP) 要解決的核心問題。
MCP 正在成為連接 AI 模型與現實世界的標準化橋梁。這套專門為大語言模型設計的協議,為模型安全、一致地接入外部數據源和工具服務提供了統一的解決方案。想象一下,你的 AI 助手不僅能回答問題,還能直接查詢數據庫、調用業務接口、生成實時報告——這正是 MCP 帶來的變革。
在技術選型上,Java 生態憑借其成熟的企業級能力和強大的類型系統,為構建生產就緒的 MCP 服務器提供了理想的基礎。特別是 Spring AI 框架的 MCP 支持,讓開發者能夠基于熟悉的技術棧構建可靠、可擴展的智能服務。
一、深入理解 MCP 協議
MCP 不僅僅是一個技術協議,它代表了一種全新的 AI 應用架構思想。與傳統的 REST API 不同,MCP 從設計之初就充分考慮了大語言模型的使用場景和特性。
協議設計的三個核心洞察:
- 語義化交互:MCP 使用工具(Tools)、資源(Resources)和提示模板(Prompts)這些對 AI 友好的抽象,讓模型能夠理解每個接口的用途和使用方式。
- 標準化通信:通過統一的 JSON-RPC 2. 0 協議,MCP 確保了不同系統之間的互操作性,避免了每個服務都要自定義接口的碎片化問題。
- 安全優先:MCP 內置了認證和授權機制,確保企業數據在 AI 交互過程中的安全性。
從技術實現視角看,MCP 的每個"能力"本質上都是一個精心設計的遠程函數。開發者需要提供清晰的 Schema(定義輸入輸出結構)和豐富的元信息描述,讓大語言模型能夠理解:這個工具是做什么的?什么時候使用?需要什么參數?返回什么結果?
這種設計哲學使得 MCP 不僅是一個技術標準,更是一種促進人機協作的交互范式。它讓 AI 系統從被動的問答機器轉變為能夠主動操作業務系統的智能助手。
二、Spring AI MCP技術優勢
在技術選型過程中,我們選擇了 Spring AI MCP 而非 Python 生態的 FastMCP,這背后有著深層的技術考量和企業需求分析。
為什么選擇 Java + Spring AI 技術棧?
(1)類型安全的堅實保障
Java 的強類型系統在構建企業級應用時提供了無可替代的優勢。編譯期的類型檢查能夠捕獲大部分潛在錯誤,這在處理復雜的業務邏輯和數據轉換時尤為重要。想象一下,在金融或醫療等對準確性要求極高的場景中,類型安全不是可選項,而是必選項。
(2)成熟的依賴注入體系
Spring 框架的 IOC 容器讓組件管理和依賴注入變得優雅而高效。這種設計模式特別適合 MCP 服務器的架構,因為工具服務通常需要依賴數據庫連接、外部 API 客戶端、配置管理等多個組件。
(3)企業集成的豐富生態
Spring 生態提供了與各種企業系統集成的成熟解決方案。無論是數據庫訪問(Spring Data)、消息隊列(Spring Integration)、安全認證(Spring Security)還是監控管理(Spring Boot Actuator),都有現成的組件可以復用。
(4)生產環境的完備支持
從配置管理、健康檢查到性能監控和日志追蹤,Spring Boot 提供了一整套生產就緒的特性。這些功能對于確保 MCP 服務器在真實業務環境中的穩定運行至關重要。
(5)團隊技術棧的延續性
對于已經擁有 Java 技術積累的團隊,使用 Spring AI MCP 可以最大限度地利用現有知識和工具鏈,降低學習成本,加快項目交付速度。
三、實戰演練
3.1 環境準備與項目初始化
讓我們從最基礎的環境搭建開始。首先確保你的開發環境滿足以下要求:
- JDK 17 或更高版本
- Maven 3.6+ 或 Gradle 7+
- 支持 Spring Boot 3.x 的 IDE
創建項目時,我們建議使用 Spring Initializr 生成項目骨架,確保依賴版本的一致性。在 pom.xml 中,除了基礎的 Spring Boot 依賴,我們還需要添加 MCP 相關的特定依賴。
依賴選擇的深層考量:
選擇 spring-ai-mcp-server-spring-boot-starter 而不是基礎的手動配置,是因為 starter 提供了自動配置、合理的默認值以及與 Spring 生態的無縫集成。這顯著降低了配置復雜度,讓開發者能夠專注于業務邏輯的實現。
創建SpringBoot項目,添加如下核心依賴。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
</dependencies>3.2 核心服務架構設計
在實現具體功能之前,我們需要理解 Spring AI MCP 服務器的核心架構組件:
// Application.java - 服務啟動入口
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
publicclass Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public ToolCallbackProvider mathTools(MathService mathService) {
return MethodToolCallbackProvider.builder()
.toolObjects(mathService)
.build();
}
}這個簡單的啟動類背后包含了 Spring AI MCP 的智能設計:
- 自動配置機制:Spring Boot 會自動配置 MCP 服務器端點、消息處理和傳輸層
- 工具發現系統:通過
ToolCallbackProvider自動掃描和注冊所有帶有@Tool注解的方法 - 生命周期管理:Spring 容器負責組件的創建、依賴注入和銷毀
3.3 業務工具的實現
工具(Tools)是 MCP 服務器的核心能力載體。每個工具都應該設計得專注、可復用且易于理解。
// MathService.java - 數學計算工具
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
@Service
publicclass MathService {
@Tool(name = "add", description = "Add two integers and return the sum")
public int add(
@ToolParam(description = "First integer operand") int a,
@ToolParam(description = "Second integer operand") int b) {
// 輸入驗證和業務邏輯處理
if (a < 0 || b < 0) {
thrownew IllegalArgumentException("Negative numbers are not supported");
}
return a + b;
}
@Tool(name = "multiply", description = "Multiply two numbers and return the product")
public double multiply(
@ToolParam(description = "First number") double a,
@ToolParam(description = "Second number") double b) {
// 處理浮點數精度問題
BigDecimal result = BigDecimal.valueOf(a).multiply(BigDecimal.valueOf(b));
return result.doubleValue();
}
}工具設計的最佳實踐:
- 清晰的命名和描述:工具名稱應該直觀,描述應該準確說明功能、輸入輸出和可能的副作用。
- 完善的參數注解:每個參數都應該有詳細的描述,幫助 AI 模型理解何時以及如何提供這個參數。
- 健壯的錯誤處理:工具應該能夠處理各種邊界情況,并提供有意義的錯誤信息。
- 性能考慮:對于可能被頻繁調用的工具,要考慮性能優化和資源管理。
3.4 資源配置與管理策略
資源(Resources)在 MCP 中代表只讀數據,它們可以是靜態配置信息,也可以是基于參數的動態數據。
// ResourceService.java - 資源管理服務
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Service
publicclass ResourceService {
@Tool(name = "get_version", description = "Retrieve current server version and build information")
public Map<String, Object> getVersion() {
return Map.of(
"version", "1.0.0",
"build_time", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
"environment", "production"
);
}
@Tool(name = "get_user_profile", description = "Retrieve detailed user profile information by user ID")
public Map<String, Object> getUserProfile(
@ToolParam(description = "Unique identifier of the user") int userId) {
// 模擬從數據庫或外部服務獲取用戶信息
// 在實際項目中,這里會集成真實的數據源
return Map.of(
"user_id", userId,
"name", "User " + userId,
"status", "active",
"created_at", "2024-01-01T00:00:00",
"last_login", LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
"permissions", new String[]{"read", "write", "execute"}
);
}
}資源設計的關鍵考慮:
- 數據一致性:確保資源數據在不同調用之間保持一致
- 緩存策略:對于不經常變化的數據,考慮實現緩存機制
- 數據脫敏:敏感信息應該在返回前進行適當的脫敏處理
- 版本管理:資源結構的變化應該考慮版本兼容性
3.5 配置管理
MCP 服務器的配置管理需要平衡靈活性和嚴謹性。我們采用分層配置策略,適應不同環境的需求。
# application.yml - 基礎配置
server:
port:8080
servlet:
context-path:/api
spring:
application:
name:mcp-server
ai:
mcp:
server:
name:enterprise-mcp-server
version:1.0.0
type:ASYNC
sse-endpoint:/sse
sse-message-endpoint:/mcp/messages
# 高級配置選項
max-concurrent-requests:100
request-timeout:30s
management:
endpoints:
web:
exposure:
include:health,info,metrics,prometheus
endpoint:
health:
show-details:always
metrics:
enabled:true
logging:
level:
org.springframework.ai:INFO
com.yourcompany.mcp:DEBUG配置設計的工程考量:
- 環境隔離:使用 Spring Profile 管理不同環境的配置
- 安全敏感信息:密碼、密鑰等敏感信息應該通過環境變量或配置中心管理
- 性能調優參數:根據預期負載調整連接數、超時時間等參數
- 監控和可觀測性:配置適當的日志級別和監控端點
四、高級特性與實踐
4.1 上下文感知的智能工具
在復雜的業務場景中,工具往往需要訪問會話上下文信息。Spring AI MCP 提供了強大的上下文支持。
// ContextAwareService.java - 上下文感知服務
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
publicclass ContextAwareService {
privatefinal RestTemplate restTemplate;
privatestaticfinal Logger logger = LoggerFactory.getLogger(ContextAwareService.class);
public ContextAwareService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Tool(name = "summarize_content",
description = "Fetch content from a URL and generate a concise summary")
public String summarizeContent(
@ToolParam(description = "URL of the content to summarize") String url) {
// 記錄詳細的操作日志
logger.info("Starting content summarization for URL: {}", url);
long startTime = System.currentTimeMillis();
try {
// 驗證 URL 格式
if (!isValidUrl(url)) {
thrownew IllegalArgumentException("Invalid URL format: " + url);
}
// 獲取遠程內容
logger.debug("Fetching content from: {}", url);
String content = fetchContentSafely(url);
if (content == null || content.trim().isEmpty()) {
return"No content available from the provided URL";
}
// 生成智能摘要
String summary = generateIntelligentSummary(content);
long processingTime = System.currentTimeMillis() - startTime;
logger.info("Successfully summarized content in {} ms", processingTime);
return String.format("Summary (%d chars): %s", summary.length(), summary);
} catch (Exception e) {
logger.error("Error summarizing content from URL: {}", url, e);
return"Error processing content: " + e.getMessage();
}
}
private boolean isValidUrl(String url) {
return url != null &&
(url.startsWith("http://") || url.startsWith("https://"));
}
private String fetchContentSafely(String url) {
try {
// 設置合理的超時時間
return restTemplate.getForObject(url, String.class);
} catch (Exception e) {
logger.warn("Failed to fetch content from URL: {}", url, e);
returnnull;
}
}
private String generateIntelligentSummary(String content) {
// 在實際項目中,這里可以集成 AI 摘要服務
// 當前實現提供基礎的文本處理
String cleanContent = content.replaceAll("\\s+", " ").trim();
// 智能截斷,盡量在句子邊界處斷開
int maxLength = 200;
if (cleanContent.length() <= maxLength) {
return cleanContent;
}
String truncated = cleanContent.substring(0, maxLength);
int lastSentenceEnd = Math.max(
truncated.lastIndexOf('.'),
Math.max(
truncated.lastIndexOf('!'),
truncated.lastIndexOf('?')
)
);
if (lastSentenceEnd > maxLength * 0.6) {
return truncated.substring(0, lastSentenceEnd + 1) + "..";
}
return truncated + "...";
}
}4.2 安全架構與認證授權
在生產環境中,安全是不可妥協的要求。我們采用多層安全防護策略。
// SecurityConfig.java - 安全配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.http.SessionCreationPolicy;
@Configuration
@EnableWebSecurity
publicclass SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 禁用 CSRF,因為 MCP 使用無狀態認證
.csrf(csrf -> csrf.disable())
// 配置會話管理為無狀態
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
// 配置請求授權
.authorizeHttpRequests(authz -> authz
// MCP 端點需要認證
.requestMatchers("/mcp/**").authenticated()
// 健康檢查端點允許匿名訪問
.requestMatchers("/actuator/health").permitAll()
// 其他 API 端點需要認證
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll()
)
// 配置 OAuth2 資源服務器
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> {
// JWT 配置可以在 application.yml 中指定
})
);
return http.build();
}
}安全設計的深度考量:
- 防御性編程:所有輸入都應該驗證,所有輸出都應該過濾
- 最小權限原則:每個工具只應該擁有完成其功能所需的最小權限
- 審計日志:記錄所有的敏感操作以便事后審計
- 密鑰管理:使用專業的密鑰管理服務,避免硬編碼密鑰
4.3 客戶端集成與測試策略
一個完整的 MCP 解決方案需要強大的客戶端支持和全面的測試覆蓋。
// MCPClientService.java - 客戶端服務
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
publicclass MCPClientService {
privatefinal ChatClient chatClient;
privatestaticfinal Logger logger = LoggerFactory.getLogger(MCPClientService.class);
public MCPClientService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public String processNaturalLanguageQuery(String userQuery) {
logger.info("Processing natural language query: {}", userQuery);
try {
String result = chatClient.prompt()
.user(userQuery)
.call()
.content();
logger.debug("Successfully processed query, result length: {}",
result != null ? result.length() : 0);
return result;
} catch (Exception e) {
logger.error("Failed to process query: {}", userQuery, e);
return"Sorry, I encountered an error while processing your request: " +
e.getMessage();
}
}
}
// TestClient.java - 集成測試客戶端
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
@Profile("dev") // 只在開發環境運行
publicclass TestClient implements CommandLineRunner {
privatefinal MCPClientService clientService;
public TestClient(MCPClientService clientService) {
this.clientService = clientService;
}
@Override
public void run(String... args) throws Exception {
System.out.println("=== MCP Server Integration Tests ===");
System.out.println();
// 測試數學計算功能
testMathOperations();
// 測試資源訪問功能
testResourceAccess();
// 測試復雜查詢處理
testComplexQueries();
System.out.println("=== All Tests Completed ===");
}
private void testMathOperations() {
System.out.println("1. Testing Math Operations:");
String[] mathQueries = {
"Calculate 15 + 25",
"What is 6.5 multiplied by 4.2?",
"Add 100 and 200 together"
};
for (String query : mathQueries) {
System.out.println(" Query: " + query);
String result = clientService.processNaturalLanguageQuery(query);
System.out.println(" Result: " + result);
System.out.println();
}
}
private void testResourceAccess() {
System.out.println("2. Testing Resource Access:");
String[] resourceQueries = {
"What version is the server running?",
"Get information for user ID 12345",
"Show me the server status"
};
for (String query : resourceQueries) {
System.out.println(" Query: " + query);
String result = clientService.processNaturalLanguageQuery(query);
System.out.println(" Result: " + result);
System.out.println();
}
}
private void testComplexQueries() {
System.out.println("3. Testing Complex Queries:");
String[] complexQueries = {
"First add 10 and 20, then multiply the result by 3",
"Get the server version and then show me user 999's profile"
};
for (String query : complexQueries) {
System.out.println(" Query: " + query);
String result = clientService.processNaturalLanguageQuery(query);
System.out.println(" Result: " + result);
System.out.println();
}
}
}4.4 與 LLM 應用集成
部署完成后,下一步是將 MCP 服務器集成到大語言模型應用中。以下示例展示如何與 OpenAI API 集成:
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.web.client.RestTemplate;
import org.springframework.stereotype.Service;
@Service
publicclass LLMIntegrationService {
privatefinal ChatClient chatClient;
privatefinal RestTemplate restTemplate;
public LLMIntegrationService(ChatClient chatClient, RestTemplate restTemplate) {
this.chatClient = chatClient;
this.restTemplate = restTemplate;
}
public String processWithLLM(String userQuery) {
// 使用 MCP 工具處理用戶查詢
String toolResult = chatClient.prompt()
.user(userQuery)
.call()
.content();
// 將結果傳遞給 LLM 進行進一步處理
String llmPrompt = String.format(
"Based on the calculation result '%s', provide a user-friendly explanation of what this means in practical terms.",
toolResult
);
// 調用外部 LLM API(示例使用模擬響應)
return enhanceWithLLM(llmPrompt);
}
private String enhanceWithLLM(String prompt) {
// 實際項目中這里會調用真實的 LLM API
// 示例中使用模擬邏輯
if (prompt.contains("calculation") || prompt.contains("result")) {
return"The calculation has been completed successfully. This result can be used for further analysis or decision making.";
}
return"I've processed your request using the available tools. Is there anything else you'd like to know?";
}
}五、部署與運維
5.1 容器化與云原生部署
現代應用部署越來越傾向于容器化和云原生架構。以下是我們的 Docker 和 Kubernetes 配置實踐。
Dockerfile 優化:
# 使用多階段構建減小鏡像大小
FROM eclipse-temurin:17-jdk as builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
# 生產階段
FROM eclipse-temurin:17-jre
WORKDIR /app
# 創建非root用戶運行應用
RUN groupadd -r spring && useradd -r -g spring spring
USER spring
# 復制構建產物
COPY --from=builder /app/target/*.jar app.jar
# 配置JVM參數
ENV JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC -XX:MaxGCPauseMillis=100"
EXPOSE8080
# 使用 exec form 啟動應用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]Kubernetes 部署配置:
# deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:mcp-server
labels:
app:mcp-server
spec:
replicas:3
selector:
matchLabels:
app:mcp-server
template:
metadata:
labels:
app:mcp-server
annotations:
prometheus.io/scrape:"true"
prometheus.io/port:"8080"
prometheus.io/path:"/actuator/prometheus"
spec:
containers:
-name:mcp-server
image:your-registry/mcp-server:latest
ports:
-containerPort:8080
env:
-name:SPRING_PROFILES_ACTIVE
value:"prod"
-name:JAVA_OPTS
value:"-Xmx512m -Xms256m"
resources:
requests:
memory:"512Mi"
cpu:"250m"
limits:
memory:"1Gi"
cpu:"500m"
livenessProbe:
httpGet:
path:/actuator/health
port:8080
initialDelaySeconds:60
periodSeconds:10
readinessProbe:
httpGet:
path:/actuator/health/readiness
port:8080
initialDelaySeconds:30
periodSeconds:5
---
apiVersion:v1
kind:Service
metadata:
name:mcp-service
spec:
selector:
app:mcp-server
ports:
-port:80
targetPort:8080
type:ClusterIP5.2 監控與可觀測性
在生產環境中,完善的監控體系是保證服務可靠性的關鍵。
應用監控配置:
# application-prod.yml - 生產環境監控配置
management:
endpoints:
web:
exposure:
include:health,info,metrics,prometheus,loggers
endpoint:
health:
show-details:always
show-components:always
metrics:
enabled:true
prometheus:
enabled:true
metrics:
export:
prometheus:
enabled:true
distribution:
percentiles-histogram:
"[http.server.requests]":true
tags:
application:${spring.application.name}
environment:prod
logging:
level:
org.springframework.ai:INFO
com.yourcompany.mcp:INFO
pattern:
level:"%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
# 自定義健康檢查指標
endpoints:
health:
custom:
mcp-connection:
enabled:true
external-api:
enabled:true六、總結
通過 Spring AI MCP,Java 開發者能夠快速構建企業級的 MCP 服務器,為大型語言模型提供穩定可靠的外部能力接入。相比 Python 方案,Java 版本在類型安全、企業集成和生產就緒方面具有顯著優勢。
無論是構建內部 AI 助手還是開發面向客戶的智能應用,Spring AI MCP 都提供了從概念驗證到生產部署的完整技術路徑。






























