jFinal 使用 SolonMCP 开发 MCP(拥抱新潮流)
<p>MCP 官方的 java-sdk 目前只支持 java17+。直接基于 mcp-java-sdk 也比较复杂。使用 SolonMCP,可以基于 java8 开发(像 MVC 的开发风格),且比较简单。</p><h3 id="1solonmcp-简介">1、SolonMCP 简介</h3>
<p>SolonMCP(全称:solon-ai-mcp)是 solon 的一个扩展。支持内嵌到 jfinal,vert.x,springboot2,springboot3 等框架使用。</p>
<p>Maven 主要依赖包:</p>
<pre><code class="language-xml"><dependency>
<groupId>org.noear</groupId>
<artifactId>solon-ai-mcp</artifactId>
</dependency>
</code></pre>
<p>具体的示例参考:</p>
<ul>
<li>https://gitee.com/opensolon/solon-ai-mcp-embedded-examples/tree/main/solon-ai-embedded-jfinal</li>
<li>https://gitee.com/opensolon/solon-ai-mcp-embedded-examples/tree/main/solon-ai-embedded-jfinal-newstyle</li>
</ul>
<h3 id="2mcp-服务端开发">2、MCP 服务端开发</h3>
<h4 id="21添加入口类-webapphelloapp比较空注意下-mcpserverconfig">2.1、添加入口类 <code>webapp.HelloApp</code>(比较空,注意下 mcpServerConfig)</h4>
<p>MCP 内部是基于响应式的,需要开启异步支持。</p>
<pre><code class="language-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();
}
</code></pre>
<h4 id="22添加-webappmcpservermcpserverconfig实现-handleriplugin-接口">2.2、添加 <code>webapp.mcpserver.McpServerConfig</code>(实现 Handler、IPlugin 接口)</h4>
<p>实现 IPlugin 对接 Solon 的生命周期。实现 Handler 对接 mcp 的请求处理。</p>
<pre><code class="language-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 = true;
}
} catch (Throwable e) {
ctx.errors = e;
throw e;
} finally {
ContextUtil.currentRemove();
}
} else {
if (next != null) {
next.handle(target, request, response, isHandled);
}
}
}
}
</code></pre>
<h4 id="23添加-webappmcpservertoolmcpserver实现-handleriplugin-接口">2.3、添加 <code>webapp.mcpserver.tool.McpServer</code>(实现 Handler、IPlugin 接口)</h4>
<p>这里是重点了,添加 mcp server 端点(支持多个端点)</p>
<pre><code class="language-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 + "'的概念?")
);
}
}
</code></pre>
<h4 id="24编译后运行">2.4、编译后运行</h4>
<p>或者开发时,直接运行 <code>HelloApp:main</code> 方法</p>
<h3 id="3mcp-客户端开发">3、MCP 客户端开发</h3>
<p>客户端简单些</p>
<pre><code class="language-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);
}
}
</code></pre>
<h3 id="4mcp-客户端作为-llmchatmodel-的工具集使用">4、MCP 客户端作为 LLM(ChatModel) 的工具集使用</h3>
<p>也比较简单。使用 ollama 做为 llm 提供者,方便本地测试。</p>
<pre><code class="language-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());
}
}
</code></pre><br><br>
来源:https://www.cnblogs.com/noear/p/18874077
頁:
[1]