jFinal 使用 SolonMCP 开发 MCP(拥抱新潮流)

MCP 官方的 java-sdk 目前只支持 java17+。直接基于 mcp-java-sdk 也比较复杂。使用 SolonMCP,可以基于 java8 开发(像 MVC 的开发风格),且比较简单。

1、SolonMCP 简介

SolonMCP(全称:solon-ai-mcp)是 solon 的一个扩展。支持内嵌到 jfinal,vert.x,springboot2,springboot3 等框架使用。

Maven 主要依赖包:

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-mcp</artifactId>
</dependency>

具体的示例参考:

2、MCP 服务端开发

2.1、添加入口类 webapp.HelloApp(比较空,注意下 mcpServerConfig)

MCP 内部是基于响应式的,需要开启异步支持。

java 复制代码
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 的请求处理。

java 复制代码
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 端点(支持多个端点)

java 复制代码
@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 客户端开发

客户端简单些

java 复制代码
public class McpClientTest {
    public static void main(String[] args) throws Exception {
        McpClientProvider toolProvider = McpClientProvider.builder()
                .apiUrl("http://localhost: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 提供者,方便本地测试。

java 复制代码
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://localhost: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());
    }
}
相关推荐
CoderYanger9 小时前
Java EE 进阶:8.MyBatis 操作数据库(入门)(第二弹)
java·数据库·spring boot·spring·面试·java-ee·mybatis
CQU_JIAKE11 小时前
11.7[高体】
java·后端·spring
不吃紫菜12 小时前
LangGraph 体系实战(上):建图、状态管理、控制流与持久化
ai
apcipot_rain12 小时前
C++转Java日记(04)
java·开发语言·c++
特立独行的猫A13 小时前
我给女儿写了个打字练习:一边敲键盘,一边把小学英语单词记牢
java·后端·python
憧憬成为java架构高手的小白14 小时前
LangGraph4j 实战(下)
java
天诰15 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
七夜zippoe15 小时前
Agent 优雅降级实战:模型不可用时的后备方案设计
ai·agent·模型·降级·后备方案
正在走向自律17 小时前
AI Agent 落地这一年:从“能跑起来”到“敢放出去”
大数据·人工智能·ai agent·智能体·mcp·a2a
这个昵称不容易18 小时前
SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在
java·springboot·毕设