搭建基于 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 (界面太多,略过...)

相关推荐
Navicat中国1 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI1 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区1 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
Pniubi2 小时前
HashMap的扩容和树化边界
java·开发语言
Mikko73 小时前
用 Java 复刻了高中时在塞班上玩的「熔岩矿车」:纯 Swing、零依赖、没有一张图片,一个 jar 双击就能玩
java·游戏开发·swing
知了学历孙老师3 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
Liaiyang663 小时前
空圈容错:从 (0, 1) 夹缝本体论到 11 次跨域盲测
ai·大模型·量子力学·科学哲学·宇宙学·认识论·认知边界
Java爱好狂.3 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试
XCDoris3 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy4 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae