用Spring Boot 搭建自己的 MCP Server

用Spring Boot 搭建自己的 MCP Server

一、创建项目Spring Boot项目

二、引入MCP Server依赖

三、最终项目结构

四、编写代码

1、创建DTO

a、创建文言文对象ArticleDTO.java

java 复制代码
public record ArticleDTO(
// 标题
String title,
// 内容
String content
) {
}

b、创建古诗词对象PoetryDTO.java

java 复制代码
public record PoetryDTO(
        // 标题
        String title,
        //  作者
        String author,
        // 内容
        String content
) {
}
2、创建MCP服务

a、创建文言文服务ArticleService.java

java 复制代码
@Service
public class ArticleService {

    private final List<ArticleDTO> articleList = new ArrayList<>();

    @PostConstruct
    public void init() {
        List<ArticleDTO> articles = List.of(
                new ArticleDTO("论语十则", "子曰:"学而时习之,不亦说(yuè)乎?有朋自远方来,不亦乐(lè)乎?人不知而不愠(yùn),不亦君子乎?" 曾子曰:"吾(wú)日三省 (xǐng) 吾 (wú) 身:为(wèi)人谋而不忠乎?与朋友交而不信乎?传(chuán)不习乎?" 子曰:"温故而知新,可以为师矣 (yǐ) 。" 子曰:"学而不思则罔(wǎng),思而不学则殆 (dài)。" 子曰:"由,诲女(rǔ)知之乎!知之为知之,不知为不知,是知(zhì)也。" 子曰:"见贤思齐焉,见不贤而内自省(xǐng)也。" 子曰:"三人行,必有我师焉。择其善者而从之,其不善者而改之。" 曾子曰:"士不可以不弘毅,任重而道远。仁以为己任,不亦重乎?死而后已,不亦远乎?" 子曰:"岁寒,然后知松柏之后凋也。" 子贡问曰:"有一言而可以终身行之者乎?" 子曰:"其恕乎!己所不欲,勿施于人。""),
                new ArticleDTO("木兰诗", "唧唧复唧唧,木兰当户织。不闻机杼声,惟闻女叹息。问女何所思,问女何所忆。女亦无所思,女亦无所忆。昨夜见军帖 (tiě),可汗大点兵,军书十二卷,卷卷有爷名。阿爷无大儿,木兰无长兄,愿为市鞍马,从此替爷征。东市买骏马,西市买鞍鞯 (jiān),南市买辔头,北市买长鞭。旦辞爷娘去,暮宿黄河边,不闻爷娘唤女声,但闻黄河流水鸣溅溅 (jiàn)。旦辞黄河去,暮至黑山头,不闻爷娘唤女声,但闻燕山胡骑鸣啾啾。万里赴戎机,关山度若飞。朔气传金柝,寒光照铁衣。将军百战死,壮士十年归。归来见天子,天子坐明堂。策勋十二转,赏赐百千强。可汗问所欲,木兰不用尚书郎;愿驰千里足,送儿还故乡。爷娘闻女来,出郭相扶将 (jiāng);阿姊闻妹来,当户理红妆;小弟闻姊来,磨刀霍霍向猪羊。开我东阁门,坐我西阁床,脱我战时袍,着我旧时裳,当窗理云鬓,对镜帖 (贴) 花黄。出门看火(伙)伴,火伴皆惊忙:同行十二年,不知木兰是女郎。雄兔脚扑朔,雌兔眼迷离;双兔傍 (bàng) 地走,安能辨我是雄雌?"),
                new ArticleDTO("陋室铭", "山不在高,有仙则名。水不在深,有龙则灵。斯是陋室,惟吾德馨。苔痕上阶绿,草色入帘青。谈笑有鸿儒,往来无白丁。可以调素琴,阅金经。无丝竹之乱耳,无案牍之劳形。南阳诸葛庐,西蜀子云亭。孔子云:"何陋之有?""),
                new ArticleDTO("爱莲说", "水陆草木之花,可爱者甚蕃。晋陶渊明独爱菊。自李唐来,世人甚爱牡丹。予独爱莲之出淤泥而不染,濯清涟而不妖,中通外直,不蔓不枝,香远益清,亭亭净植,可远观而不可亵玩焉。予谓菊,花之隐逸者也;牡丹,花之富贵者也;莲,花之君子者也。菊之爱,陶后鲜有闻。莲之爱,同予者何人?牡丹之爱,宜乎众矣。"),
                new ArticleDTO("小石潭记", "从小丘西行百二十步,隔篁竹,闻水声,如鸣珮环,心乐之。全石以为底,近岸,卷石底以出,为坻,为屿,为嵁,为岩。潭中鱼可百许头,皆若空游无所依,日光下澈,影布石上。佁然不动,俶尔远逝,往来翕忽,似与游者相乐。潭西南而望,斗折蛇行,明灭可见。其岸势犬牙差互,不可知其源。坐潭上,四面竹树环合,寂寥无人,凄神寒骨,悄怆幽邃。以其境过清,不可久居,乃记之而去。"),
                new ArticleDTO("岳阳楼记", "予观夫巴陵胜状,在洞庭一湖。衔远山,吞长江,浩浩汤汤,横无际涯;朝晖夕阴,气象万千。此则岳阳楼之大观也,前人之述备矣。然则北通巫峡,南极潇湘,迁客骚人,多会于此,览物之情,得无异乎?若夫霪雨霏霏,连月不开,阴风怒号,浊浪排空;日星隐曜,山岳潜形;商旅不行,樯倾楫摧;薄暮冥冥,虎啸猿啼。登斯楼也,则有去国怀乡,忧谗畏讥,满目萧然,感极而悲者矣。至若春和景明,波澜不惊,上下天光,一碧万顷;沙鸥翔集,锦鳞游泳;岸芷汀兰,郁郁青青。而或长烟一空,皓月千里,浮光跃金,静影沉璧,渔歌互答,此乐何极!登斯楼也,则有心旷神怡,宠辱偕忘,把酒临风,其喜洋洋者矣。嗟夫!予尝求古仁人之心,或异二者之为,何哉?不以物喜,不以己悲;居庙堂之高则忧其民;处江湖之远则忧其君。是进亦忧,退亦忧。然则何时而乐耶?其必曰 "先天下之忧而忧,后天下之乐而乐" 乎。微斯人,吾谁与归?时六年九月十五日。"),
                new ArticleDTO("醉翁亭记", "环滁皆山也。其西南诸峰,林壑尤美,望之蔚然而深秀者,琅琊也。山行六七里,渐闻水声潺潺而泻出于两峰之间者,酿泉也。峰回路转,有亭翼然临于泉上者,醉翁亭也。作亭者谁?山之僧智仙也。名之者谁?太守自谓也。太守与客来饮于此,饮少辄醉,而年又最高,故自号曰醉翁也。醉翁之意不在酒,在乎山水之间也。山水之乐,得之心而寓之酒也。若夫日出而林霏开,云归而岩穴暝,晦明变化者,山间之朝暮也。野芳发而幽香,佳木秀而繁阴,风霜高洁,水落而石出者,山间之四时也。朝而往,暮而归,四时之景不同,而乐亦无穷也。临溪而渔,溪深而鱼肥。酿泉为酒,泉香而酒洌;山肴野蔌,杂然而前陈者,太守宴也。宴酣之乐,非丝非竹,射者中,弈者胜,觥筹交错,起坐而喧哗者,众宾欢也。苍颜白发,颓然乎其间者,太守醉也。已而夕阳在山,人影散乱,太守归而宾客从也。树林阴翳,鸣声上下,游人去而禽鸟乐也。然而禽鸟知山林之乐,而不知人之乐;人知从太守游而乐,而不知太守之乐其乐也。醉能同其乐,醒能述以文者,太守也。太守谓谁?庐陵欧阳修也。"),
                new ArticleDTO("桃花源记", "晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,渔人甚异之,复前行,欲穷其林。林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田美池桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:"不足为外人道也。" 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终,后遂无问津者。"),
                new ArticleDTO("逍遥游", "北冥有鱼,其名曰鲲。鲲之大,不知其几千里也。化而为鸟,其名为鹏。鹏之背,不知其几千里也;怒而飞,其翼若垂天之云。是鸟也,海运则将徙于南冥。南冥者,天池也。《齐谐》者,志怪者也。《谐》之言曰:"鹏之徙于南冥也,水击三千里,抟扶摇而上者九万里,去以六月息者也。" 野马也,尘埃也,生物之以息相吹也。天之苍苍,其正色邪?其远而无所至极邪?其视下也,亦若是则已矣。且夫水之积也不厚,则其负大舟也无力。覆杯水于坳堂之上,则芥为之舟;置杯焉则胶,水浅而舟大也。风之积也不厚,则其负大翼也无力。故九万里,则风斯在下矣,而后乃今培风;背负青天而莫之夭阏者,而后乃今将图南。蜩与学鸠笑之曰:"我决起而飞,抢榆枋而止,时则不至而控于地而已矣,奚以之九万里而南为?" 适莽苍者,三餐而反,腹犹果然;适百里者,宿舂粮;适千里者,三月聚粮。之二虫又何知!小知不及大知,小年不及大年。奚以知其然也?朝菌不知晦朔,蟪蛄不知春秋,此小年也。楚之南有冥灵者,以五百岁为春,五百岁为秋;上古有大椿者,以八千岁为春,八千岁为秋,此大年也。而彭祖乃今以久特闻,众人匹之,不亦悲乎!"),
                new ArticleDTO("生于忧患,死于安乐", "舜发于畎亩之中,傅说举于版筑之间,胶鬲举于鱼盐之中,管夷吾举于士,孙叔敖举于海,百里奚举于市。故天将降大任于是人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,曾益其所不能。人恒过,然后能改;困于心,衡于虑,而后作;征于色,发于声,而后喻。入则无法家拂士,出则无敌国外患者,国恒亡。然后知生于忧患,而死于安乐也。")
        );

        articleList.addAll(articles);
    }

    @Tool(name = "articleAllList", description = "获取文言文列表")
    public List<ArticleDTO> articleAllList() {
        return articleList;
    }

    @Tool(name = "article", description = "根据标题获取文言文")
    public ArticleDTO article(String title) {
        return articleList.stream()
                .filter(article -> article.title().equals(title))
                .findFirst()
                .orElse(null);
    }
}

b、创建古诗词服务PoetryService.java

java 复制代码
@Service
public class PoetryService {

    private final List<PoetryDTO> poetryList = new ArrayList<>();

    @PostConstruct
    public void init() {
        List<PoetryDTO> poetrys = List.of(
                new PoetryDTO("静夜思", "唐·李白", "床前明月光,疑是地上霜。举头望明月,低头思故乡。"),
                new PoetryDTO("春晓", "唐·孟浩然", "春眠不觉晓,处处闻啼鸟。夜来风雨声,花落知多少。"),
                new PoetryDTO("江雪", "唐·柳宗元", "千山鸟飞绝, 万径人踪灭。 孤舟蓑笠翁, 独钓寒江雪。"),
                new PoetryDTO("登鹳雀楼", "唐·王之涣", "白日依山尽,黄河入海流。欲穷千里目,更上一层楼。"),
                new PoetryDTO("鹿柴", "唐·王维", "空山不见人,但闻人语响。返景入深林,复照青苔上。"),
                new PoetryDTO("游子吟", "唐·孟郊", "慈母手中线,游子身上衣。临行密密缝,意恐迟迟归。谁言寸草心,报得三春晖。"),
                new PoetryDTO("八阵图", "唐·杜甫", "功盖三分国,名成八阵图。江流石不转,遗恨失吞吴。"),
                new PoetryDTO("咏柳", "唐·贺知章", "碧玉妆成一树高,万条垂下绿丝绦。不知细叶谁裁出,二月春风似剪刀。"),
                new PoetryDTO("清明", "唐·杜牧", "清明时节雨纷纷,路上行人欲断魂。借问酒家何处有,牧童遥指杏花村。"),
                new PoetryDTO("乌衣巷", "唐·刘禹锡", "朱雀桥边野草花,乌衣巷口夕阳斜。旧时王谢堂前燕,飞入寻常百姓家。"),
                new PoetryDTO("池上", "唐·白居易", "小娃撑小艇,偷采白莲回。不解藏踪迹,浮萍一道开。"),
                new PoetryDTO("关山月", "唐·李白", "明月出天山,苍茫云海间。长风几万里,吹度玉门关。汉下白登道,胡窥青海湾。由来征战地,不见有人还。戍客望边邑,思归多苦颜。高楼当此夜,叹息未应闲。"),
                new PoetryDTO("宿建德江", "唐·孟浩然", "移舟泊烟渚,日暮客愁新。野旷天低树,江清月近人。")
        );

        poetryList.addAll(poetrys);
    }

    @Tool(name = "poetryAllList", description = "获取古诗词列表")
    public List<PoetryDTO> poetryAllList() {
        return poetryList;
    }

    @Tool(name = "poetryList", description = "根据标题、作者或内容获取古诗词")
    public List<PoetryDTO> poetryList(String title) {
        return poetryList.stream()
                .filter(poetry -> poetry.title().contains(title) || poetry.author().contains(title) || poetry.content().contains(title))
                .toList();
    }

    @Tool(name = "poetry", description = "根据标题获取古诗词")
    public PoetryDTO poetry(String title) {
        return poetryList.stream()
                .filter(poetry -> poetry.title().equals(title))
                .findFirst()
                .orElse(null);
    }
}
3、创建MCP配置McpServerConfig.java
java 复制代码
@Configuration
public class McpServerConfig {
    @Bean
    public List<ToolCallback> tools(ApplicationContext applicationContext) {
        Map<String, Object> toolBeans = applicationContext.getBeansWithAnnotation(Service.class);
        return List.of(ToolCallbacks.from(toolBeans.values().toArray()));
    }
}
4、启动类McpServerApplication.java
java 复制代码
@SpringBootApplication
public class McpServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(McpServerApplication.class, args);
    }

}
5、application.yml
yaml 复制代码
spring:
  ai:
    mcp:
      server:
        name: solar-mcp-server
        version: 1.0.0
  application:
    name: solar-mcp-server
  main:
    banner-mode: off
    web-application-type: none

logging:
  pattern:
    console:
6、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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.4</version>
        <relativePath/>
    </parent>

    <groupId>com.msgcm</groupId>
    <artifactId>solar-mcp-server</artifactId>
    <version>1.0.0</version>

    <name>solar-mcp-server</name>
    <description>solar-mcp-server</description>

    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.1</spring-ai.version>
        <lombok.version>1.18.38</lombok.version>
    </properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <build>
        <finalName>solar-mcp-server</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
为了方便起见,我在每个Service中添加了默认的初始化数据,你可以根据需要自行修改。比如从数据库查询数据或者从文件获取数据等方式获取数据。
McpServerConfig直接获取所有Service,并转换为ToolCallback,一劳永逸。
以上便是一个简单的MCP服务端示例,你可以根据需要自行修改。

五、打包并配置MCP Server

1、打包:在项目根目录下执行 mvn clean package -DskipTests

将打包后的jar复制到固定的运行目录,我这里放在:D:\test

2、配置MCP Server

如果需要配置MCP Server,首先得有一个大模型的环境,这里直接使用IDEA中的通义灵码插件(也可以用其他大模型的插件),然后配置MCP Server。 具体怎么安装就不赘述了,这里只介绍如何配置MCP Server。

1、打开IDEA中的通义灵码插件,然后点击MCP 工具,配置MCP Server。

当然也可以点击个人设置,然后点击MCP Server,配置MCP Server。

2、配置MCP Server,点击+号,选择手动添加。

3、填写MCP Server的配置信息,这里我填写的是D:\test\solar-mcp-server.jar。

点击立即添加后,MCP Server会自动执行java -jar D:\test\solar-mcp-server.jar,等待一会儿后就自动连接上了。 连接上后可以看到MCP Server的配置信息。

六、测试MCP 服务

直接在通义聊天窗口输入就行。

可以看到获取的古诗词都是我们MCP Server中的数据。

再来看一个例子:

继续下一个例子:

可以看到,上面所有的回答内容都是从我们自己写的MCP Server中的数据中获取整理后得到的。

至此,就是MCP Server的搭建过程。

你学废了么?

相关推荐
louisgeek11 分钟前
Java UnmodifiableList 和 AbstractImmutableList 的区别
java
回家路上绕了弯44 分钟前
深度理解 Lock 与 ReentrantLock:Java 并发编程的高级锁机制
java·后端
青云交1 小时前
Java 大视界 -- Java 大数据在智能教育在线课程互动优化与学习体验提升中的应用(386)
java·大数据·flink·在线课程·智能教育·互动优化·学习体验
期待のcode1 小时前
SpringAOP
java·开发语言·spring
Captaincc1 小时前
TRAE 首场 Meetup:8月16日,期待与你在北京相聚
前端·后端·trae
肩塔didi2 小时前
用 Pixi 管理 Python 项目:打通Conda 和 PyPI 的边界
后端·python·github
岁忧2 小时前
(LeetCode 面试经典 150 题) 104. 二叉树的最大深度 (深度优先搜索dfs)
java·c++·leetcode·面试·go·深度优先
麦兜*2 小时前
内存杀手机器:TensorFlow Lite + Spring Boot移动端模型服务深度优化方案
java·人工智能·spring boot·spring cloud·ai·tensorflow·ai编程
dylan_QAQ2 小时前
【附录】相对于BeanFactory ,ApplicationContext 做了哪些企业化的增强?
后端·spring
夏小花花2 小时前
Java 日常开发笔记(小程序页面交互传参-id)
java·微信小程序·vue