MCP 官方的 java-sdk 目前只支持 java17+。直接基于 mcp-java-sdk 也比较复杂。使用 SolonMCP,可以基于 java8 开发(像 MVC 的开发风格),且比较简单。
1、SolonMCP 简介
SolonMCP(全称:solon-ai-mcp)是 solon 的一个扩展。支持内嵌到 jfinal,vert.x,springboot2,springboot3 等框架使用。
Maven 主要依赖包:
<dependency> <groupId>org.noear</groupId> <artifactId>solon-ai-mcp</artifactId></dependency>
具体的示例参考:
2、MCP 服务端开发
2.1、添加入口类 webapp.HelloApp
(比较空,注意下 mcpServerConfig)
MCP 内部是基于响应式的,需要开启异步支持。
public class HelloApp extends JFinalConfig { public static void main(String[] args) { UndertowServer.create(HelloApp.class) .setDevMode(false) .setPort(8080) .onDeploy((cl, di) -> { di.getFilters().get("jfinal").setAsyncSupported(true); //注意这个,要开启异步支持 }).start(); } public void configConstant(Constants me) { me.setDevMode(false); } public void configRoute(Routes me) { } public void configEngine(Engine me) { } public void configPlugin(Plugins me) { me.add(mcpServerConfig); } public void configInterceptor(Interceptors me) { } public void configHandler(Handlers me) { me.add(mcpServerConfig); } private McpServerConfig mcpServerConfig = new McpServerConfig();}
2.2、添加 webapp.mcpserver.McpServerConfig
(实现 Handler、IPlugin 接口)
实现 IPlugin 对接 Solon 的生命周期。实现 Handler 对接 mcp 的请求处理。
public class McpServerConfig extends Handler implements IPlugin { public boolean start() { Solon.start(McpServerConfig.class, new String[]{"--cfg=mcpserver.yml"}); return true; } public boolean stop() { if (Solon.app() != null) { Solon.stopBlock(false, Solon.cfg().stopDelay()); } return true; } @Override public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { if (target.startsWith("/mcp/")) { Context ctx = new SolonServletContext(request, response); try { //Solon处理(可能是空处理) Solon.app().tryHandle(ctx); if (isHandled != null && isHandled.length > 0) { isHandled[0] = true; } } catch (Throwable e) { ctx.errors = e; throw e; } finally { ContextUtil.currentRemove(); } } else { if (next != null) { next.handle(target, request, response, isHandled); } } }}
2.3、添加 webapp.mcpserver.tool.McpServer
(实现 Handler、IPlugin 接口)
这里是重点了,添加 mcp server 端点(支持多个端点)
@McpServerEndpoint(sseEndpoint = "/mcp/sse")public class McpServer { // // 建议开启编译参数:-parameters (否则,最好再配置参数的 name) // @ToolMapping(description = "查询天气预报") public String getWeather(@Param(description = "城市位置") String location) { return "晴,14度"; } @ResourceMapping(uri = "config://app-version", description = "获取应用版本号") public String getAppVersion() { return "v3.2.0"; } @ResourceMapping(uri = "db://users/{user_id}/email", description = "根据用户ID查询邮箱") public String getEmail(@Param(description = "用户Id") String user_id) { return user_id + "@example.com"; } @PromptMapping(description = "生成关于某个主题的提问") public Collection<ChatMessage> askQuestion(@Param(description = "主题") String topic) { return Arrays.asList( ChatMessage.ofUser("请解释一下'" + topic + "'的概念?") ); }}
2.4、编译后运行
或者开发时,直接运行 HelloApp:main
方法
3、MCP 客户端开发
客户端简单些
public class McpClientTest { public static void main(String[] args) throws Exception { McpClientProvider toolProvider = McpClientProvider.builder() .apiUrl("http://lo**c*alhost:8080/mcp/sse") .build(); //工具调用 Map<String, Object> map = Collections.singletonMap("location", "杭州"); String rst = toolProvider.callToolAsText("getWeather", map).getContent(); System.out.println(rst); assert "晴,14度".equals(rst); //资源读取 resourceContent = toolProvider.readResourceAsText("config://app-version").getContent(); System.out.println(resourceContent); }}
4、MCP 客户端作为 LLM(ChatModel) 的工具集使用
也比较简单。使用 ollama 做为 llm 提供者,方便本地测试。
public class McpClientTest { private static final String apiUrl = "http://127.*0.**0.1:11434/api/chat"; private static final String provider = "ollama"; private static final String model = "qwen2.5:1.5b"; //"llama3.2";//deepseek-r1:1.5b; public static void main(String[] args) throws Exception { //构建 mcp client McpClientProvider toolProvider = McpClientProvider.builder() .apiUrl("http://lo**c*alhost:8080/mcp/sse") .build(); //构建 llm 接口 ChatModel chatModel = ChatModel.of(apiUrl) .provider(provider) .model(model) .defaultToolsAdd(toolProvider) //添加默认工具(这是 mcp client) .build(); //请求 ChatResponse resp = chatModel.prompt("杭州今天的天气怎么样?") .call(); System.out.println(resp.getMessage()); }}