Java MCP 实战:构建跨进程与远程的工具服务

一、MCP 协议简介

MCP(Model Context Protocol,模型上下文协议)是由Anthropic推出的一种开放标准协议,旨在为大语言模型(LLM)与外部数据源、工具和服务提供标准化、安全的集成方式。支持进程间(通过 stdio)和远程(通过 HTTP SSE/Streaming)通讯。它专为 AI 开发设计,可以方便地提供 Tool(工具服务)、Prompt(提示语服务)和 Resource(资源服务)三种原语内容。

MCP 的核心优势在于:

  • 支持多种通讯方式(stdio/SSE/Streaming)
  • 支持服务发现(客户端可查询服务端点提供的接口)
  • 与 AI 生态无缝集成(可直接作为大模型的工具使用)

MCP 架构示意图:

二、环境准备

首先在项目中添加 Java MCP 关键依赖:

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-mcp</artifactId>
    <version>最新版本</version>
</dependency>

支持 java8, java11, java17, java21, java24 。支持 solon,springboot,vert.x,jFinal 等框架集成。完整的示例参考:

三、构建 MCP 服务端

1、最简单的 SSE 服务

java 复制代码
@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、多端点服务

java 复制代码
// 金融工具服务
@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、动态管理工具

java 复制代码
@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 服务

java 复制代码
@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、基本客户端调用

java 复制代码
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模型

java 复制代码
@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、三种原语内容

java 复制代码
@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、代理模式

java 复制代码
// 将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互通

java 复制代码
@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端点

java 复制代码
@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、客户端配置

java 复制代码
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、断线重连:客户端默认支持断线重连,可通过心跳机制保持连接

java 复制代码
@McpServerEndpoint(sseEndpoint = "/mcp/sse", heartbeatInterval = "60s")
public class HeartbeatService {
    // ...
}

七、总结

通过本文,我们学习了如何使用 Java 和 Solon MCP 构建强大的工具服务:

  • 可以创建多种类型的服务端点(SSE/STDIO)
  • 支持动态添加和移除工具
  • 可与 Web API 无缝集成
  • 支持代理模式实现协议转换
  • 提供完整的鉴权和配置方案

MCP 协议特别适合需要与 AI 系统集成的场景,能够将现有服务快速暴露给大模型使用,同时也支持传统的程序间调用。其灵活的通讯方式(进程内/远程)和原语支持(工具/提示/资源)使其成为构建现代分布式系统的有力工具。

在实际项目中,可以根据需求选择 SSE 或 STDIO 通讯方式,或者结合两者使用代理模式。对于需要与 AI 集成的场景,MCP 提供的工具服务描述机制能够大大简化集成工作。

相关推荐
CodeAmaz5 分钟前
Spring编程式事务详解
java·数据库·spring
没有bug.的程序员7 分钟前
微服务基础设施清单:必须、应该、可以、无需的四级分类指南
java·jvm·微服务·云原生·容器·架构
武子康10 分钟前
Java-204 RabbitMQ Connection/Channel 工作流程:AMQP 发布消费、抓包帧结构与常见坑
java·分布式·消息队列·rabbitmq·ruby·java-activemq
郑州光合科技余经理11 分钟前
海外国际版同城服务系统开发:PHP技术栈
java·大数据·开发语言·前端·人工智能·架构·php
appearappear22 分钟前
Mac 上重新安装了Cursor 2.2.30,重新配置 springboot 过程记录
java·spring boot·后端
CryptoRzz30 分钟前
日本股票 API 对接实战指南(实时行情与 IPO 专题)
java·开发语言·python·区块链·maven
程序员水自流33 分钟前
MySQL数据库自带系统数据库功能介绍
java·数据库·mysql·oracle
谷哥的小弟37 分钟前
Spring Framework源码解析——RequestContext
java·后端·spring·框架·源码
天远Date Lab43 分钟前
Java微服务实战:聚合型“全能小微企业报告”接口的调用与数据清洗
java·大数据·python·微服务
lizz311 小时前
C++操作符重载深度解析
java·c++·算法