目录
使用Spring AI和MCP协议构建图片搜索服务
引言
技术栈概览
项目架构设计
架构图
服务端开发
1. 创建Spring Boot项目
2. 实现图片搜索工具
3. 配置传输模式
Stdio模式(本地调用)
SSE模式(远程调用)
4. 注册工具提供者
5. 单元测试
6. 打包服务
客户端开发
1. 引入MCP客户端依赖
2. 配置MCP服务连接
Stdio模式(本地调用)
SSE模式(远程调用)
3. 绑定MCP工具至ChatClient
4. 测试客户端
实现效果展示
Stdio模式测试结果
SSE模式测试结果
对话示例
高级功能扩展
1. 图片过滤功能
2. 图片合成与处理
部署最佳实践
本地部署
远程部署
Serverless部署
性能优化建议
安全性考虑
总结
使用Spring AI和MCP协议构建图片搜索服务
引言
随着大型语言模型(LLM)在各行业的应用不断深入,如何让AI能够获取和处理多模态信息成为了重要课题。图片搜索作为常见的多模态场景,是一个理想的实践案例。本文将详细介绍如何结合Spring AI框架与MCP协议,构建一个功能完整的图片搜索服务,使LLM能够根据用户需求搜索并展示相关图片。
技术栈概览
本项目主要使用以下技术:
- Spring Boot:提供基础框架支持
- Spring AI:集成AI能力与MCP协议
- Pexels API:提供图片搜索功能
- MCP协议:标准化工具调用接口
- Hutool:提供HTTP请求等工具支持
项目架构设计
我们将构建的系统分为两部分:
- MCP服务端:提供图片搜索功能,对外暴露标准MCP接口
- MCP客户端:集成在业务应用中,调用MCP服务并处理结果
架构图
+----------------+ MCP协议 +----------------+ HTTP +----------------+
| | <-------------> | | <---------> | |
| 应用程序 | | 图片搜索 | | Pexels API |
| (MCP客户端) | | MCP服务 | | |
+----------------+ +----------------+ +----------------+
服务端开发
1. 创建Spring Boot项目
首先,创建一个Spring Boot项目,并添加必要的依赖:
<!-- Spring AI MCP 服务端 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
<!-- HTTP工具库 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.8.26</version>
</dependency>
2. 实现图片搜索工具
创建一个核心服务类ImageSearchTool
,封装Pexels API的调用:
@Service
public class ImageSearchTool {
// 从官网申请获得的Pexels API密钥
// 实际应用中应从环境变量或配置中心读取,避免硬编码
private static final String API_KEY = "api key";
// Pexels 搜索接口URL
private static final String API_URL = "https://api.pexels.com/v1/search";
/**
* 提供给MCP协议的图片搜索工具
* 使用@Tool注解标记为工具,并提供描述信息
*
* @param query 搜索关键词
* @return 图片URL列表,以逗号分隔
*/
@Tool(description = "search image from web")
public String searchImage(@ToolParam(description = "Search query keyword") String query) {
try {
return String.join(",", searchMediumImages(query));
} catch (Exception e) {
return "Error search image: " + e.getMessage();
}
}
/**
* 搜索中等尺寸的图片列表
*
* @param query 搜索关键词
* @return 图片URL列表
*/
public List<String> searchMediumImages(String query) {
// 设置请求头(包含API密钥)
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", API_KEY);
// 设置请求参数
Map<String, Object> params = new HashMap<>();
params.put("query", query);
// 发送 GET 请求
String response = HttpUtil.createGet(API_URL)
.addHeaders(headers)
.form(params)
.execute()
.body();
// 解析响应JSON,提取图片URL
return JSONUtil.parseObj(response)
.getJSONArray("photos")
.stream()
.map(photoObj -> (JSONObject) photoObj)
.map(photoObj -> photoObj.getJSONObject("src"))
.map(photo -> photo.getStr("medium"))
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
}
/**
* 搜索完整尺寸和更多元数据的图片
* 可用于高级场景
*/
public Map<String, Object> searchImagesWithDetails(String query, int perPage) {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", API_KEY);
Map<String, Object> params = new HashMap<>();
params.put("query", query);
params.put("per_page", perPage);
String response = HttpUtil.createGet(API_URL)
.addHeaders(headers)
.form(params)
.execute()
.body();
JSONObject result = JSONUtil.parseObj(response);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("total_results", result.getInt("total_results"));
resultMap.put("page", result.getInt("page"));
resultMap.put("per_page", result.getInt("per_page"));
List<Map<String, Object>> photos = new ArrayList<>();
result.getJSONArray("photos").forEach(photo -> {
JSONObject photoObj = (JSONObject) photo;
Map<String, Object> photoMap = new HashMap<>();
photoMap.put("id", photoObj.getInt("id"));
photoMap.put("width", photoObj.getInt("width"));
photoMap.put("height", photoObj.getInt("height"));
photoMap.put("url", photoObj.getStr("url"));
photoMap.put("photographer", photoObj.getStr("photographer"));
photoMap.put("medium_url", photoObj.getJSONObject("src").getStr("medium"));
photoMap.put("original_url", photoObj.getJSONObject("src").getStr("original"));
photos.add(photoMap);
});
resultMap.put("photos", photos);
return resultMap;
}
}
3. 配置传输模式
MCP支持两种传输模式:Stdio和SSE。我们需要根据应用场景选择合适的模式:
Stdio模式(本地调用)
适用于本地开发环境或单机部署场景,通过标准输入输出进行通信。
# application.yml
spring:
ai:
mcp:
server:
name: image-search-mcp-server
version: 0.0.1
stdio: true
main:
web-application-type: none
SSE模式(远程调用)
适用于分布式环境或多客户端共享的生产场景,通过HTTP Server-Sent Events进行通信。
# application.yml
spring:
ai:
mcp:
server:
name: image-search-mcp-server
version: 0.0.1
stdio: false
server:
port: 8127
两种模式各有优势,可以根据部署环境和使用场景灵活选择:
传输模式 | 优点 | 缺点 | 适用场景 |
Stdio | 简单部署、低延迟 | 需维护多个服务实例 | 开发测试、单用户应用 |
SSE | 易共享、可扩展 | 依赖网络稳定性 | 生产环境、多用户共享 |
4. 注册工具提供者
在Spring Boot主类中注册工具提供者:
@SpringBootApplication
public class ImageSearchMcpServerApplication {
public static void main(String[] args) {
SpringApplication.run(ImageSearchMcpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider imageSearchTools(ImageSearchTool imageSearchTool) {
return MethodToolCallbackProvider.builder()
.toolObjects(imageSearchTool)
.build();
}
}
5. 单元测试
创建单元测试验证功能:
@SpringBootTest
public class ImageSearchToolTest {
@Resource
private ImageSearchTool imageSearchTool;
@Test
void searchImage() {
String result = imageSearchTool.searchImage("computer");
String[] urlArray = result.split(",");
for (int i = 0; i < urlArray.length; i++) {
String markdownUrl = "";
System.out.println(markdownUrl);
}
}
}
6. 打包服务
使用Maven命令打包MCP服务:
mvn clean package
打包后的JAR文件位于target/image-search-mcp-server-0.0.1-SNAPSHOT.jar
。
客户端开发
现在我们已经完成了MCP服务端的开发,接下来需要实现客户端,将图片搜索能力集成到AI应用中。
1. 引入MCP客户端依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
2. 配置MCP服务连接
根据部署方式,选择不同的配置:
Stdio模式(本地调用)
创建resources/mcp-servers.json
文件:
{
"mcpServers": {
"image-search-mcp-server": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-Dlogging.pattern.console=",
"-jar",
"path/to/image-search-mcp-server-0.0.1-SNAPSHOT.jar"
],
"env": {}
}
}
}
在application.yml
中配置:
spring:
ai:
mcp:
client:
stdio:
servers-configuration: classpath:mcp-servers.json
SSE模式(远程调用)
spring:
ai:
mcp:
client:
sse:
connections:
server1:
url: http://localhost:8127
3. 绑定MCP工具至ChatClient
在AI应用中集成MCP工具:
@Service
@Slf4j
public class AiAssistantService {
@Resource
private ChatClient chatClient;
@Resource
private ToolCallbackProvider toolCallbackProvider;
public String doChatWithMcp(String message, String chatId) {
ChatResponse response = chatClient
.prompt()
.user(message)
.advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
// 开启日志,便于观察效果
.advisors(new MyLoggerAdvisor())
.tools(toolCallbackProvider)
.call()
.chatResponse();
String content = response.getResult().getOutput().getText();
log.info("content: {}", content);
return content;
}
}
4. 测试客户端
编写单元测试验证客户端功能:
@SpringBootTest
class AiAssistantServiceTest {
@Autowired
private AiAssistantService aiAssistantService;
@Test
void doChatWithMcp() {
String chatId = UUID.randomUUID().toString();
// 测试图片搜索 MCP
String message = "帮我搜索一些关于自然风景的图片";
String answer = aiAssistantService.doChatWithMcp(message, chatId);
System.out.println(answer);
assertNotNull(answer);
}
}
实现效果展示
成功实现后,系统可以支持以下场景:
- 基本图片搜索:用户请求搜索特定主题的图片
- 多图搜索:一次返回多张相关图片
- 主题识别:理解用户描述的主题并进行相关搜索
Stdio模式测试结果
使用本地Stdio模式运行MCP服务并集成到Spring AI应用中:
SSE模式测试结果
将MCP服务部署为远程HTTP服务并通过SSE方式调用:
对话示例
用户: 帮我搜索一些哄另一半开心的图片
AI: 我已经为您搜索了一些可以哄另一半开心的图片,请看:

public String searchImagesWithFilters(
@ToolParam(description = "Search query keyword") String query,
@ToolParam(description = "Image orientation (landscape/portrait/square)") String orientation,
@ToolParam(description = "Image size (large/medium/small)") String size,
@ToolParam(description = "Maximum number of images") Integer maxImages
) {
// 实现过滤逻辑
}
2. 图片合成与处理
结合其他服务进行图片处理:
@Tool(description = "process and enhance image")
public String enhanceImage(
@ToolParam(description = "Image URL to process") String imageUrl,
@ToolParam(description = "Enhancement type (brighten/crop/resize)") String enhancementType
) {
// 实现图片处理逻辑
}
部署最佳实践
本地部署
适用于开发测试环境:
- 打包MCP服务JAR文件
- 配置客户端使用Stdio模式
- 在客户端启动时自动启动MCP服务
远程部署
适用于生产环境:
- 将MCP服务部署为独立服务
- 配置客户端使用SSE模式连接
- 实现服务健康检查和自动重试
Serverless部署
适用于弹性需求场景:
- 部署到云函数平台(如阿里云FC)
- 配置按需自动扩缩容
- 节约资源成本
性能优化建议
- 连接池管理:对HTTP请求使用连接池
- 缓存机制:对热门搜索词结果进行缓存
- 超时控制:设置合理的API调用超时
- 指标监控:加入性能监控指标收集
安全性考虑
- API密钥保护:避免硬编码,使用环境变量
- 请求验证:验证搜索参数,防止注入攻击
- 结果过滤:确保返回内容符合预期
- 访问限制:添加调用频率限制
总结
通过Spring AI和MCP协议,我们成功构建了一个功能完整的图片搜索服务,使AI应用能够轻松获取和展示图片资源。这种模式不仅提高了AI的实用性,还为开发者提供了一种标准化、可复用的工具集成方式。
参考资料:
- Spring AI 官方文档
- Pexels API 文档
- MCP 协议规范
作者:lenyan
GitHub:lenyanjgk (lenyanjgk) · GitHub
CSDN:lenyan~-CSDN博客