一、MCP 协议简介
MCP(Model Context Protocol,模型上下文协议)是由Anthropic推出的一种开放标准协议,旨在为大语言模型(LLM)与外部数据源、工具和服务提供标准化、安全的集成方式。支持进程间(通过 stdio)和远程(通过 HTTP SSE/Streaming)通讯。它专为 AI 开发设计,可以方便地提供 Tool(工具服务)、Prompt(提示语服务)和 Resource(资源服务)三种原语内容。
MCP 的核心优势在于:
- 支持多种通讯方式(stdio/SSE/Streaming)
- 支持服务发现(客户端可查询服务端点提供的接口)
- 与 AI 生态无缝集成(可直接作为大模型的工具使用)
MCP 架构示意图:
二、环境准备
首先在项目中添加 Java MCP 关键依赖:- <dependency>
- <groupId>org.noear</groupId>
- solon-ai-mcp</artifactId>
- <version>最新版本</version>
- </dependency>
复制代码 支持 java8, java11, java17, java21, java24 。支持 solon,springboot,vert.x,jFinal 等框架集成。完整的示例参考:
- https://gitee.com/solonlab/solon-ai-mcp-embedded-examples
- https://gitcode.com/solonlab/solon-ai-mcp-embedded-examples
- https://github.com/solonlab/solon-ai-mcp-embedded-examples
三、构建 MCP 服务端
1、最简单的 SSE 服务
- @McpServerEndpoint(sseEndpoint = "/mcp/sse")
- public class SimpleMcpServer {
- @ToolMapping(description = "问候服务")
- public String hello(@Param(name="name", description = "用户名") String name) {
- return "你好, " + name;
- }
- }
- public class App {
- public static void main(String[] args) {
- Solon.start(App.class, args);
- }
- }
复制代码 2、多端点服务
- // 金融工具服务
- @McpServerEndpoint(name="finance-tools", sseEndpoint = "/finance/sse")
- public class FinanceTools {
- @ToolMapping(description = "计算复利")
- public double compoundInterest(
- @Param(description = "本金") double principal,
- @Param(description = "年利率") double rate,
- @Param(description = "年数") int years) {
- return principal * Math.pow(1 + rate, years);
- }
- }
- // 教育工具服务
- @McpServerEndpoint(name="edu-tools", sseEndpoint = "/edu/sse")
- public class EducationTools {
- @ToolMapping(description = "生成数学题")
- public String generateMathProblem(
- @Param(description = "难度级别") String level) {
- if("easy".equals(level)) {
- return "3 + 5 = ?";
- } else {
- return "∫(x^2)dx from 0 to 1 = ?";
- }
- }
- }
复制代码 3、动态管理工具
- @Controller
- public class ToolManager {
- @Inject("finance-tools")
- McpServerEndpointProvider financeEndpoint;
-
- @Mapping("/tool/add")
- public void addTool() {
- financeEndpoint.addTool(new FunctionToolDesc("calculateTax")
- .doHandle(params -> {
- double income = (double)params.get("income");
- return income * 0.2; // 简单计算20%税
- }));
- financeEndpoint.notifyToolsListChanged();
- }
-
- @Mapping("/tool/remove")
- public void removeTool() {
- financeEndpoint.removeTool("calculateTax");
- financeEndpoint.notifyToolsListChanged();
- }
- }
复制代码 4、STDIO 服务
- @McpServerEndpoint(channel = McpChannel.STDIO)
- public class StdioCalculator {
- @ToolMapping(description = "加法计算")
- public int add(@Param int a, @Param int b) {
- return a + b;
- }
-
- @ToolMapping(description = "减法计算")
- public int subtract(@Param int a, @Param int b) {
- return a - b;
- }
- }
复制代码 注意:STDIO 服务不能开启控制台日志,否则会污染协议流。
四、构建 MCP 客户端
1、基本客户端调用
- public class McpClientDemo {
- public static void main(String[] args) {
- // 连接SSE服务
- McpClientToolProvider sseClient = McpClientToolProvider.builder()
- .apiUrl("http://localhost:8080/mcp/sse")
- .build();
-
- String greeting = sseClient.callToolAsText("hello", Map.of("name", "张三"));
- System.out.println(greeting);
-
- // 连接STDIO服务
- McpClientToolProvider stdioClient = McpClientToolProvider.builder()
- .channel(McpChannel.STDIO)
- .serverParameters(McpServerParameters.builder("java")
- .args("-jar", "path/to/stdio-service.jar")
- .build())
- .build();
-
- int sum = stdioClient.callToolAsText("add", Map.of("a", 5, "b", 3));
- System.out.println("5 + 3 = " + sum);
- }
- }
复制代码 2、集成到AI模型
- @Configuration
- public class AiConfig {
- @Bean
- public ChatModel chatModel(
- @Inject("${solon.ai.chat.config}") ChatConfig chatConfig,
- @Inject("mcp-weather") McpClientToolProvider toolProvider) {
-
- return ChatModel.of(chatConfig)
- .defaultToolsAdd(toolProvider.getTools())
- .build();
- }
-
- @Bean("mcp-weather")
- public McpClientToolProvider weatherToolProvider() {
- return McpClientToolProvider.builder()
- .apiUrl("http://weather-service/mcp/sse")
- .build();
- }
- }
- @Service
- public class WeatherService {
- @Inject
- ChatModel chatModel;
-
- public String askWeather(String question) {
- ChatResponse response = chatModel.prompt(question).call();
- return response.getContent();
- }
- }
复制代码 五、高级特性
1、三种原语内容
- @McpServerEndpoint(sseEndpoint = "/mcp/sse")
- public class FullFeatureServer {
- // 工具服务
- @ToolMapping(description = "汇率转换")
- public double exchangeRate(
- @Param(description = "源货币") String from,
- @Param(description = "目标货币") String to) {
- // 实现汇率转换逻辑
- return 6.5;
- }
-
- // 资源服务
- @ResourceMapping(uri = "config://app-info",
- description = "获取应用信息")
- public String getAppInfo() {
- return "AppName: WeatherService, Version: 1.0.0";
- }
-
- // 提示语服务
- @PromptMapping(description = "生成天气报告提示")
- public Collection<ChatMessage> weatherReportPrompt(
- @Param(description = "城市名称") String city) {
- return Arrays.asList(
- ChatMessage.ofSystem("你是一个天气报告助手"),
- ChatMessage.ofUser("请生成" + city + "的天气报告")
- );
- }
- }
复制代码 2、代理模式
- // 将STDIO服务代理为SSE服务
- @McpServerEndpoint(sseEndpoint = "/proxy/sse")
- public class StdioToSseProxy implements ToolProvider {
- private McpClientProvider stdioClient = McpClientProvider.builder()
- .channel(McpChannel.STDIO)
- .serverParameters(ServerParameters.builder("java")
- .args("-jar", "path/to/stdio-service.jar")
- .build())
- .build();
-
- @Override
- public Collection<FunctionTool> getTools() {
- return stdioClient.getTools();
- }
- }
- // 将SSE服务代理为STDIO服务
- @McpServerEndpoint(channel = McpChannel.STDIO)
- public class SseToStdioProxy implements ToolProvider {
- private McpClientProvider sseClient = McpClientProvider.builder()
- .apiUrl("http://remote-service/mcp/sse")
- .build();
-
- @Override
- public Collection<FunctionTool> getTools() {
- return sseClient.getTools();
- }
- }
复制代码 3、与Web API互通
- @Controller
- @McpServerEndpoint(sseEndpoint = "/mcp/sse")
- public class HybridService {
- // 同时作为Web API和MCP工具
- @ToolMapping(description = "查询库存")
- @Mapping("/api/inventory")
- public int getInventory(
- @Param(description = "产品ID") String productId,
- @Header("Authorization") String auth) {
- // 验证逻辑...
- return 100; // 示例库存
- }
-
- // 纯Web API
- @Mapping("/api/info")
- public String getInfo() {
- return "Service Info";
- }
-
- // 纯MCP工具
- @ToolMapping(description = "计算折扣")
- public double calculateDiscount(
- @Param(description = "原价") double price,
- @Param(description = "会员等级") String level) {
- if("VIP".equals(level)) {
- return price * 0.8;
- }
- return price;
- }
- }
复制代码 六、生产环境注意事项
1、鉴权设计:使用过滤器保护MCP端点
- @Component
- public class McpAuthFilter implements Filter {
- @Override
- public void doFilter(Context ctx, FilterChain chain) throws Throwable {
- if (ctx.pathNew().startsWith("/mcp/")) {
- String apiKey = ctx.header("X-API-KEY");
- if(!validateApiKey(apiKey)) {
- ctx.status(401);
- return;
- }
- }
- chain.doFilter(ctx);
- }
- }
复制代码 2、客户端配置
- McpClientToolProvider.builder()
- .apiUrl("http://service/mcp/sse")
- .apiKey("your-api-key")
- .httpTimeout(HttpTimeout.builder()
- .connectTimeout(Duration.ofSeconds(5))
- .readTimeout(Duration.ofSeconds(30))
- .build())
- .requestTimeout(Duration.ofSeconds(20))
- .build();
复制代码 3、断线重连:客户端默认支持断线重连,可通过心跳机制保持连接
- @McpServerEndpoint(sseEndpoint = "/mcp/sse", heartbeatInterval = "60s")
- public class HeartbeatService {
- // ...
- }
复制代码 七、总结
通过本文,我们学习了如何使用 Java 和 Solon MCP 构建强大的工具服务:
- 可以创建多种类型的服务端点(SSE/STDIO)
- 支持动态添加和移除工具
- 可与 Web API 无缝集成
- 支持代理模式实现协议转换
- 提供完整的鉴权和配置方案
MCP 协议特别适合需要与 AI 系统集成的场景,能够将现有服务快速暴露给大模型使用,同时也支持传统的程序间调用。其灵活的通讯方式(进程内/远程)和原语支持(工具/提示/资源)使其成为构建现代分布式系统的有力工具。
在实际项目中,可以根据需求选择 SSE 或 STDIO 通讯方式,或者结合两者使用代理模式。对于需要与 AI 集成的场景,MCP 提供的工具服务描述机制能够大大简化集成工作。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |