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 关键依赖:
<dependency>
<groupId>org.noear</groupId>
<artifactId>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 提供的工具服务描述机制能够大大简化集成工作。
Java MCP 实战:构建跨进程与远程的工具服务的更多相关文章
- Android跨进程訪问(AIDL服务)
我将AndroidAIDL的学习知识总结一下和大家共享 在Android开发中,AIDL主要是用来跨进程訪问. Android系统中的进程之间不能共享内存,因此,须要提供一些机制在不同进程之间进行数据 ...
- AIDL-Android接口描述语言实现跨进程通讯
在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢? 显然, Java中不允许跨进程内存共享. 因此传递对象, ...
- android 远程Service以及AIDL的跨进程通信
在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问 ...
- [Hook] 跨进程 Binder设计与实现 - 设计篇
cp from : http://blog.csdn.net/universus/article/details/6211589 关键词 Binder Android IPC Linux 内核 驱动 ...
- AIDL跨进程通信
Android跨进程通信会用到AIDL,当然跨进程通信不一定要用AIDL,像广播也是可以的,当然这里用到AIDL相对比较安全一些: AIDL允许传递基本数据类型(Java 的原生类型如int/long ...
- 跨进程通信之Messenger
1.简介 Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了.Messenger是一种轻量级 ...
- 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇
前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...
- Android 跨进程数据共享
Android 开发过程中,基于功能隔离.进程安全.进程保活等等考虑,我们经常需要为应用划分进程,然后不得不面临跨进程通信和跨进程共享数据的挑战. 跨进程通信 相对来说,跨进程通信比较简单,常用的方式 ...
- Android四大组件应用系列5——使用AIDL实现跨进程调用Service
一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentPr ...
- Android-Messenger跨进程通信
http://blog.csdn.net/lmj623565791/article/details/47017485 一.概述 我们可以在客户端发送一个Message给服务端,在服务端的handler ...
随机推荐
- Log4j2 重大漏洞,编译好的log4j-2.15.0.jar包下载
背景 12 月 10 日凌晨,Apache 开源项目 Log4j 的远程代码执行漏洞细节被公开,由于 Log4j 的广泛使用,该漏洞一旦被攻击者利用会造成严重危害.受本次漏洞影响的版本范围为Apach ...
- nodejs中使用websockets
websockets介绍 websockets这个新协议为客户端提供了一个更快.更有效的通信线路.像HTTP一样,websockets运行在TCP连接之上,但是它们更快,因为我们不必每次都打开一个新的 ...
- Elasticsearch7.6.1配套安装包自取
包含Elasticsearch,ik分词器,kibana 7.6.1安装包自取:https://pan.baidu.com/s/1Y6XdDOzqIzI2qerOODQHmg提取码:5nm4
- [开源] .Net 使用 ORM 访问 人大金仓数据库
前言 京人大金仓信息技术股份有限公司(以下简称"人大金仓")是具有自主知识产权的国产数据管理软件与服务提供商.人大金仓由中国人民大学一批最早在国内开展数据库教学.科研.开发的专家于 ...
- Dify 框架连接 PGSQL 数据库与 Sandbox 环境下的 Linux 系统调用权限问题
Dify 框架连接 PGSQL 数据库与 Sandbox 环境下的 Linux 系统调用权限问题 背景 在使用 Dify 框架进行开发时,遇到了两个主要的技术挑战: 代码节点连接到 PGSQL(Pos ...
- 同余最短路&转圈背包算法学习笔记(超详细)
一.问题引入 当你想要解决一个完全背包计数问题,但是 \(M\) 的范围太大,那么你就可以使用同余最短路. 二.算法推导过程 首先对于一个完全背包计数问题,我们要知道如果 \(x\) 这个数能凑出来, ...
- MCP 实践系列:EdgeOne 在线部署HTML页面
今天,我们将专门讲解一下 EdgeOne 在线部署 HTML 页面时所提供的 MCP 功能.这个功能对于个人用户来说非常实用,尤其适合一些小型应用场景,比如开发一个简单的小游戏,或者搭建一个小型网站, ...
- 国产化-消息队列RocketMq(替代kafka)-单节点安装
RocketMQ 是一款由阿里巴巴开源的分布式消息中间件,具有高可靠.高性能.高可扩展性等特点,在众多企业级应用中得到了广泛的应用.以下是对 RocketMQ 的详细介绍: 国内三大IT巨头阿里. ...
- Torch-Pruning工具箱
Torch-Pruning 通道剪枝网络实现加速的工作. Torch pruning是进行结构剪枝的pytorch工具箱,和pytorch官方提供的基于mask的非结构化剪枝不同,工具箱移除整个通道剪 ...
- ASP.NET Core之Razor Page相关
cshtml一般是这样: @page @model IndexModel @{ ViewData["Title"] = "Home page"; } <d ...