搭建基于 Solon AI 的 Streamable MCP 服务并部署至阿里云百炼

一、快速搭建 Solon 项目,引入 Solon AI

1. 开发环境准备

  • JDK 8 或以上版本。
  • Maven 3.8.6 或以上版本。
  • 通义千问 API Key(用于模型调用)。

2. 创建名为 mcp-server-demo 的项目

创建时选择 Archetype 为 Solon AI(可以减少些活),会自动添加 Solon AI、MCP 相关依赖。

创建后可以再简化下 pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.noear</groupId>
        <artifactId>solon-parent</artifactId>
        <version>3.5.1</version>
        <relativePath />
    </parent>

    <groupId>com.example</groupId>
    <artifactId>solon-bailian-mcp-workflow-server</artifactId>
    <version>1.0</version>
    
    <packaging>jar</packaging>

    <description>Demo project for Solon</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-ai-mcp</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-logging-logback</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>

        <plugins>
            <plugin>
                <groupId>org.noear</groupId>
                <artifactId>solon-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

二、添加 Mcp Server 并添加两个工具

使用 @McpServerEndpoint 注解,就像 MVC 开发一样简单。name 为 mcp-server-demo(可以按需设定),channel 使用 McpChannel.STREAMABLE(表示用 streamable 传输方式),mcpEndpoint 为 /mcp(可以按需设定)。

支持多个端点。就像 MVC 开发有多个控制器,每个控制器可以有自己的前缀地址。

java 复制代码
import org.noear.solon.Utils;
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.mcp.McpChannel;
import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint;

import java.util.List;

//工具,会再调用 dashscope 的模型。
@McpServerEndpoint(name = "mcp-server-demo", channel = McpChannel.STREAMABLE, mcpEndpoint = "/mcp")
public class McpToolServer {
    @ToolMapping(description = "批量生成标题")
    public List<String> BatchGenerateTitles(String title) {
        String SystemPrompt = "# 角色\n" +
                "你是一位专业的批量生成标题助手,擅长根据用户提供的提示快速生成高质量的标题。\n" +
                "\n" +
                "## 技能\n" +
                "### 技能1:理解用户需求\n" +
                "- 仔细阅读并理解用户提供的提示和要求。\n" +
                "- 根据用户的输入,确定标题的主题、风格和目标受众。\n" +
                "\n" +
                "### 技能2:创意标题生成\n" +
                "- 能够在短时间内生成多个具有吸引力和多样性的标题。\n" +
                "- 确保每个标题都符合用户的需求,并且能够吸引目标受众的注意力。\n" +
                "\n" +
                "### 技能3:标题优化\n" +
                "- 对生成的标题进行优化,确保它们简洁明了、易于理解。\n" +
                "- 考虑到SEO优化,合理嵌入关键词以提高标题的可发现性。\n" +
                "\n" +
                "### 技能4:多样化风格\n" +
                "- 能够生成不同风格的标题,如新闻报道式、故事叙述式、疑问式等。\n" +
                "- 根据不同的使用场景(如博客文章、社交媒体帖子、新闻报道等)调整标题的风格和长度。\n" +
                "\n" +
                "## 限制\n" +
                "- 生成的标题数量为20个。\n" +
                "- 每个标题应简洁明了,不超过20个字。\n" +
                "- 所有标题必须与用户提供的提示和要求一致。\n" +
                "- 避免使用过于复杂或难以理解的语言。\n" +
                "- 如果需要特定领域的专业知识,可以通过调用搜索工具或查询知识库来获取相关信息。";
        String UserPrompt = "用户输入内容如下:" + title;
        String reTitle = null;
        try {
            reTitle = callWithMessage(SystemPrompt, UserPrompt);
        } catch (Exception e) {
            return Utils.asList("错误:" + e.getMessage());
        }
        if (reTitle == null) {
            return Utils.asList("错误:生成标题失败");
        }
        return Utils.asList(reTitle);
    }

    @ToolMapping(description = "文章润色")
    public List<String> polishTheArticle(String content) {
        String SystemPrompt = "# 角色\n" +
                "你是一位专业的文章润色助手,擅长提升文章的语言表达、逻辑结构和整体流畅性。你的任务是根据用户提供的原始文本,进行细致的润色,使文章更加清晰、生动和有说服力。\n" +
                "\n" +
                "## 技能\n" +
                "### 技能 1: 语言润色\n" +
                "- 优化文章中的词汇选择,使其更加精准和生动。\n" +
                "- 调整句子结构,使文章更加流畅自然。\n" +
                "- 修正语法错误和拼写错误,确保文章的专业性和准确性。\n" +
                "\n" +
                "### 技能 2: 逻辑结构优化\n" +
                "- 重新组织段落顺序,使文章的逻辑更加清晰。\n" +
                "- 添加或删除内容,以增强文章的连贯性和一致性。\n" +
                "- 提供适当的过渡句,使各部分之间的衔接更加自然。\n" +
                "\n" +
                "### 技能 3: 内容丰富与精简\n" +
                "- 根据需要添加更多细节,使文章内容更加丰富和具体。\n" +
                "- 删除冗余信息,使文章更加简洁明了。\n" +
                "- 保持文章的主题和核心思想不变,同时提升其吸引力和可读性。\n" +
                "\n" +
                "### 技能 4: 风格调整\n" +
                "- 根据用户的指示调整文章的风格,如正式、幽默、轻松等。\n" +
                "- 确保文章的风格与目标受众相匹配。\n" +
                "- 保持一致的语气和语调,增强文章的整体效果。\n" +
                "\n" +
                "## 限制\n" +
                "- 只对用户提供的一篇文章进行润色,不涉及其他文档。\n" +
                "- 润色过程中保持原文的核心内容和意图不变。\n" +
                "- 不得添加或删除与文章主题无关的内容。\n" +
                "- 如果用户提供了特定的风格要求,请严格遵循这些要求进行润色。\n" +
                "- 在润色时,注意保留用户的个人风格和声音,避免过度修改。";
        String UserPrompt = "原始文本内容如下:" + content;
        String ReContent = null;
        try {
            ReContent = callWithMessage(SystemPrompt, UserPrompt);
        } catch (Exception e) {
            return Utils.asList("错误:" + e.getMessage());
        }
        if (ReContent == null) {
            return Utils.asList("错误:文章润色失败");
        }
        return Utils.asList(ReContent);
    }

    public String callWithMessage(String systemPrompt, String userPrompt) throws Exception {
        ChatModel chatModel = ChatModel.of("https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .model("qwen-plus")
                .build();

        return chatModel.prompt(ChatMessage.ofSystem(systemPrompt), ChatMessage.ofUser(userPrompt))
                .call()
                .getContent();
    }
}

提示:不需要别的配置或注册了。

三、添加测试类,简单试下效果

通过测试注解 @SolonTest(App.class) 启动服务端,通过 McpClientProvider 连接服务端并获取所有工具。

java 复制代码
import com.example.mcp_server.App;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.noear.solon.ai.chat.tool.FunctionTool;
import org.noear.solon.ai.mcp.McpChannel;
import org.noear.solon.ai.mcp.client.McpClientProvider;
import org.noear.solon.test.SolonTest;

import java.util.Collection;

@Slf4j
@SolonTest(App.class)
public class McpClientTest {
    @Test
    public void clientTest() {
        McpClientProvider clientProvider = McpClientProvider.builder()
                .url("http://localhost:8080/mcp")
                .channel(McpChannel.STREAMABLE)
                .build();

        //获取所有工具
        Collection<FunctionTool> tools = clientProvider.getTools();

        log.error("{}", tools);
    }
}

单测运行效果:

四、项目打包并部署

打包,并生成 mcp-server-demo.jar

发布到自己的服务器(可用 java -jar mcp-server-demo.jar 运行)。或者,上传到阿里云函数(界面太多,略过...)

五、将部署好的 Streamable MCP 集成到百炼当中

按照界面引导,添加配置(界面太多,略过...)。

后续,可以进一步创建智能体使用 Streamable MCP (界面太多,略过...)

相关推荐
stormsha20 小时前
裸眼3D原理浅析AI如何生成平面裸眼3D图像以科幻战士破框而出为例
人工智能·计算机视觉·平面·3d·ai
20岁30年经验的码农21 小时前
Spring Cloud Gateway 网关技术文档
java
likuolei1 天前
XML DOM 节点类型
xml·java·服务器
春日见1 天前
丝滑快速拓展随机树 S-RRT(Smoothly RRT)算法核心原理与完整流程
人工智能·算法·机器学习·路径规划算法·s-rrt
ZHE|张恒1 天前
Spring Bean 生命周期
java·spring
陈文锦丫1 天前
MixFormer: A Mixed CNN–Transformer Backbone
人工智能·cnn·transformer
小毅&Nora1 天前
【人工智能】【AI外呼】系统架构设计与实现详解
人工智能·系统架构·ai外呼
q***38511 天前
SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
java·spring cloud·gateway
小白学大数据1 天前
Python爬虫伪装策略:如何模拟浏览器正常访问JSP站点
java·开发语言·爬虫·python
jianqiang.xue1 天前
别把 Scratch 当 “动画玩具”!图形化编程是算法思维的最佳启蒙
人工智能·算法·青少年编程·机器人·少儿编程