ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Spring Boot服务如何改造成AI可调用的MCP工具

Spring Boot服务如何改造成AI可调用的MCP工具

1. 为什么要把Spring Boot服务改造成AI可调用的工具

1.1 一个真实的需求场景

手头有一套跑了两年多的Spring Boot订单系统,接口稳定、日志齐全、权限体系也完善。某天团队想用AI助手做一个“智能客服”,让AI能直接查订单状态、改收货地址、发起退款。第一反应是写个中间层,把HTTP接口包装成AI能理解的格式,但很快发现这条路走不通——每接一个新AI平台就要重写一遍适配层,工具描述、参数Schema、调用协议全都不一样,维护成本高得离谱。

这个问题的本质是:AI应用和业务服务之间缺少一个统一的“工具描述与调用协议”。传统做法是每个AI平台自己定义一套Function Calling格式,业务方被迫为每个平台做适配。MCP(Model Context Protocol)要解决的就是这件事——它定义了一套标准协议,让业务服务用统一的方式“声明”自己有哪些能力,AI应用用统一的方式“发现”和“调用”这些能力。

把Spring Boot服务变成MCP工具,意味着你的订单查询、用户管理、支付接口,可以被任何支持MCP的AI应用直接调用,不需要为每个平台单独写适配代码。这对后端团队来说,是把已有资产盘活的关键一步。

1.2 MCP到底解决了什么问题

用一句话概括:MCP是AI应用和外部工具之间的“USB-C接口”。

在MCP出现之前,AI应用要调用外部能力,通常有三种做法。第一种是硬编码,把工具逻辑直接写在AI应用的代码里,耦合度极高。第二种是自定义HTTP接口,AI应用通过提示词告诉模型“你可以调用这个URL”,但参数格式、错误处理、鉴权方式全靠约定,换个模型就可能失效。第三种是各平台自己的插件体系,比如某些AI平台有自己的工具注册机制,但互不兼容。

MCP的价值在于标准化。它规定了三件事:工具如何描述(名称、参数、返回值)、工具如何被发现(列表查询)、工具如何被调用(请求与响应格式)。只要你的服务实现了MCP协议,任何支持MCP的AI客户端都能直接接入,不需要改一行AI侧的代码。

对于Spring Boot开发者来说,这意味着你不需要学习每个AI平台的插件开发规范,只需要按照MCP的标准把服务暴露出来,剩下的交给协议本身。

1.3 适合哪些人参考

这篇内容适合三类读者。第一类是后端开发者,手上有现成的Spring Boot服务,想快速接入AI能力,但不想被某个AI平台绑定。第二类是AI应用开发者,需要为自己的Agent寻找可靠的工具来源,理解MCP服务端是怎么实现的,有助于排查调用问题。第三类是技术负责人,在评估“自研工具协议”还是“采用MCP标准”时,需要了解落地成本和实际效果。

前置知识方面,你需要熟悉Spring Boot的基本开发(Controller、Service、配置类),了解JSON Schema的基本概念,对AI应用的Function Calling机制有初步认知。不需要你懂大模型训练,也不需要你深入理解MCP的底层传输细节,跟着做就能跑通。

2. MCP的核心概念与Spring Boot的映射关系

2.1 MCP的三个核心角色

MCP协议里定义了三个角色:Host、Client、Server。Host是AI应用本身,比如一个对话助手;Client是Host内部负责与Server通信的模块;Server就是提供工具的一方,也就是我们要用Spring Boot实现的部分。

这个划分很关键,因为它决定了职责边界。Server只负责“声明能力”和“执行能力”,不关心AI怎么决策、怎么组织对话。Host和Client负责发现工具、把工具描述传给模型、解析模型的调用意图、把调用请求转发给Server。这种分离让Server的实现可以非常纯粹——你只需要把业务逻辑包装成MCP规定的格式即可。

在Spring Boot的语境下,Server就是一个独立的Spring Boot应用,或者是你现有应用中的一个模块。它对外暴露MCP协议规定的接口,对内调用你已有的Service层。

2.2 工具、资源与提示模板

MCP Server可以暴露三种类型的能力:Tools、Resources、Prompts。

Tools是最常用的,代表“可执行的操作”,比如查询订单、创建用户、发送通知。每个Tool有名称、描述、输入参数的JSON Schema。AI应用会把Tool的描述传给模型,模型决定是否调用、传什么参数。

Resources代表“可读取的数据”,比如文件内容、数据库记录、配置信息。Resources通常是只读的,AI应用可以请求读取某个资源,但不应该通过Resources修改状态。

Prompts是预定义的提示模板,Server可以提供一些常用的提示词片段,供Host使用。实际项目中Prompts用得相对少,Tools和Resources是重点。

对于大多数Spring Boot服务来说,你已有的Controller方法大致对应Tools,已有的查询接口大致对应Resources。映射关系并不复杂,关键是理解每个Tool的输入输出都要用JSON Schema描述清楚。

2.3 传输层:stdio与HTTP

MCP支持多种传输方式,最常用的是stdio和HTTP with SSE。

stdio方式下,MCP Server作为一个子进程启动,通过标准输入输出与Client通信。这种方式适合本地工具,部署简单,不需要网络配置。但缺点是Server和Client必须在同一台机器上,不适合分布式场景。

HTTP with SSE方式下,Server是一个HTTP服务,Client通过HTTP请求发送调用,通过Server-Sent Events接收流式响应。这种方式适合远程服务,可以独立部署、独立扩缩容。对于Spring Boot服务来说,HTTP方式是更自然的选择,因为Spring Boot本身就是干这个的。

选择哪种传输方式,取决于你的部署形态。如果AI应用和Spring Boot服务在同一台机器上,stdio更简单;如果是微服务架构或者需要远程调用,HTTP是唯一选择。后面的实操部分我会以HTTP方式为主,因为它的适用场景更广。

2.4 Spring Boot与MCP的对应关系表

MCP概念Spring Boot对应物说明
ToolController方法每个Tool对应一个可执行的操作
Tool输入SchemaDTO类的字段定义用JSON Schema描述参数类型和约束
Tool执行Service层方法调用实际的业务逻辑
Resource查询接口/配置文件只读数据的暴露
ServerSpring Boot应用承载所有Tool和Resource
ClientAI应用内部模块不需要我们实现
传输层HTTP端点Spring Boot的Web能力

这张表的核心目的是帮你建立直觉:你不需要从零学一套新东西,MCP的概念在Spring Boot里都有对应物,你要做的是把已有的东西“翻译”成MCP能理解的格式。

3. 从零搭建一个MCP Server的完整实操

3.1 项目初始化与依赖选择

先创建一个标准的Spring Boot项目。我用的版本是Spring Boot 3.2.x,JDK 17。依赖方面,除了常规的spring-boot-starter-web,还需要引入MCP的Java SDK。目前社区里有几个可选的实现,我选的是官方维护的mcp-java-sdk,版本用最新的稳定版。

<dependency> <groupId>io.modelcontextprotocol</groupId> <artifactId>mcp-server-spring-boot-starter</artifactId> <version>0.10.0</version> </dependency>

这个starter会自动配置MCP的HTTP端点、SSE通道、以及工具注册的基础设施。如果你不想用starter,也可以手动引入核心包,自己配置传输层,但那样工作量会大很多,除非你有特殊的定制需求,否则建议直接用starter。

注意:MCP的Java SDK还在快速迭代中,不同版本之间的API可能有变化。建议锁定一个版本,不要频繁升级,等稳定后再考虑迁移。

项目结构上,我建议单独建一个模块或者单独建一个应用,不要和现有的业务应用混在一起。原因是MCP Server的职责是“暴露能力”,它应该是一个薄层,调用现有的Service,而不是把业务逻辑重新写一遍。单独部署也方便你做权限控制和流量隔离。

3.2 定义第一个Tool:订单查询

假设我们有一个订单服务,已经有一个OrderService,里面有个方法getOrderById(Long orderId)返回订单详情。现在要把它暴露成MCP Tool。

第一步是定义Tool的输入参数。MCP要求用JSON Schema描述参数,但在Java里我们通常用注解或者配置类来生成Schema。我选的方式是定义一个DTO,用Jackson的注解描述字段,SDK会自动生成Schema。

public class GetOrderInput { @JsonProperty(required = true, value = "order_id") @JsonPropertyDescription("订单的唯一标识,纯数字") private Long orderId; // getter and setter }

这里有个细节:字段名用下划线风格(order_id)而不是驼峰,因为JSON Schema的惯例是下划线,而且很多AI模型对下划线命名的参数理解更好。@JsonPropertyDescription的内容会直接出现在Schema的description字段里,模型会根据这个描述来判断什么时候该调用这个Tool、该传什么参数。所以描述要写得具体,不要写“订单ID”这种模糊的话,要写“订单的唯一标识,纯数字”。

第二步是定义Tool的执行逻辑。SDK提供了@Tool注解,标注在方法上即可。

@Component public class OrderTools { private final OrderService orderService; public OrderTools(OrderService orderService) { this.orderService = orderService; } @Tool(name = "get_order", description = "根据订单ID查询订单详情,返回订单状态、金额、收货地址等信息") public OrderDetail getOrder(GetOrderInput input) { return orderService.getOrderById(input.getOrderId()); } }

@Tool注解的name是工具的唯一标识,AI应用通过这个名字来调用。description是给模型看的,要写清楚这个工具能做什么、返回什么。方法参数是输入DTO,返回值是输出对象,SDK会自动把返回值序列化成JSON。

第三步是注册Tool。如果用starter,@Component标注的类会被自动扫描,@Tool方法会被自动注册。不需要额外的配置。

启动应用后,访问MCP的tools/list端点,应该能看到get_order这个工具,以及它的输入Schema。这一步验证通过,说明基础链路是通的。

3.3 参数校验与错误处理

Tool的参数校验不能只靠Schema。Schema只能描述类型和必填,但业务规则(比如订单ID必须大于0、状态必须是枚举值)需要在代码里校验。

@Tool(name = "get_order", description = "...") public OrderDetail getOrder(GetOrderInput input) { if (input.getOrderId() == null || input.getOrderId() <= 0) { throw new McpToolException("订单ID必须为正整数"); } OrderDetail detail = orderService.getOrderById(input.getOrderId()); if (detail == null) { throw new McpToolException("订单不存在"); } return detail; }

McpToolException是SDK提供的异常类,抛出后会被转换成MCP协议规定的错误响应,AI应用能收到结构化的错误信息,而不是一个500错误页面。这一点很重要,因为模型需要根据错误信息决定下一步怎么做——是重试、还是告诉用户“订单不存在”、还是换一个工具。

错误信息要写得对模型友好。不要写“NullPointerException at line 42”,要写“订单不存在,请确认订单ID是否正确”。模型看到后者,才能给出有意义的回复。

实操心得:我习惯在Tool方法里做三层校验——第一层是Schema层面的类型校验,第二层是业务规则校验(比如ID范围、状态合法性),第三层是权限校验(当前用户是否有权访问这个订单)。前两层在Tool方法里做,第三层建议放在Service层,因为权限逻辑通常和业务逻辑耦合更紧。

3.4 把Resource也暴露出来

除了Tools,Resources也值得暴露。比如“当前用户的订单列表”可以作为一个Resource,AI应用可以读取它,但不应该通过它修改数据。

@Resource(uri = "order://current-user/orders", name = "当前用户订单列表", description = "返回当前登录用户的所有订单摘要") public List<OrderSummary> getCurrentUserOrders() { return orderService.getOrdersByCurrentUser(); }

Resource的URI是自定义的,用order://这种scheme是为了和HTTP URL区分开。AI应用通过resources/read端点读取Resource内容,返回的是JSON数据。

Resources和Tools的区别在于语义:Tools是“做一件事”,Resources是“读一份数据”。模型在决策时,如果只是需要信息,应该优先读Resource;如果需要执行操作,才调用Tool。这个区分有助于模型做出更合理的决策。

4. 让AI应用真正调用起来的联调过程

4.1 用MCP Inspector做本地验证

在接入真正的AI应用之前,先用MCP Inspector做验证。Inspector是一个命令行工具,可以连接MCP Server,列出所有Tools和Resources,手动调用并查看返回结果。

npx @modelcontextprotocol/inspector http://localhost:8080/mcp

启动后,Inspector会显示一个交互界面,左侧是Tools列表,右侧是调用面板。选中get_order,输入{"order_id": 123},点击调用,应该能看到订单详情返回。如果报错,Inspector会显示错误信息,方便定位问题。

这一步的价值在于:它把“MCP协议层”和“AI应用层”分开了。如果Inspector能调通,说明Server实现没问题,问题出在AI应用侧;如果Inspector调不通,说明Server的Tool定义或传输层配置有问题。这种分层排查能省很多时间。

4.2 接入AI应用:以对话助手为例

假设你有一个支持MCP的对话助手,配置方式通常是在配置文件里加上MCP Server的地址。

{ "mcpServers": { "order-service": { "url": "http://localhost:8080/mcp", "transport": "http" } } }

配置完成后,助手启动时会自动连接MCP Server,拉取Tools列表,把每个Tool的描述注入到模型的系统提示里。当用户说“帮我查一下订单123的状态”,模型会识别出需要调用get_order,生成调用请求,助手把请求转发给MCP Server,拿到结果后再交给模型生成回复。

这个过程中,你不需要写任何AI侧的代码。模型怎么决策、怎么组织语言,是AI应用的事;你只需要保证Tool的描述准确、参数Schema清晰、返回结果结构化。

4.3 联调中常见的坑

第一个坑是Tool描述太模糊。比如描述写“查询订单”,模型可能不知道什么时候该用这个Tool,或者传错参数。描述要写清楚:这个Tool做什么、输入是什么、输出是什么、有什么限制。我通常会把描述写成一段完整的话,而不是几个关键词。

第二个坑是参数命名不一致。Schema里写order_id,但代码里用orderId,SDK如果没做自动转换,就会导致参数绑定失败。建议统一用下划线风格,或者在DTO上明确标注@JsonProperty。

第三个坑是返回结果太大。如果Tool返回一个包含几百个字段的对象,模型处理起来会很吃力,而且容易超出上下文限制。建议返回精简后的DTO,只包含模型需要的信息。比如订单详情里,模型可能只需要订单号、状态、金额、收货地址,不需要创建时间、更新时间、操作人等内部字段。

第四个坑是错误信息不结构化。如果Tool抛出未捕获的异常,MCP协议会返回一个通用的错误,模型无法理解具体原因。建议所有业务异常都转换成McpToolException,并附带清晰的错误描述。

避坑技巧:在开发阶段,把MCP Server的日志级别调到DEBUG,可以看到每个请求的完整内容和响应。联调时先看日志,再看Inspector,最后才怀疑AI应用。大部分问题都出在Server侧。

5. 生产环境部署与性能考量

5.1 部署形态选择

MCP Server的部署形态取决于你的AI应用在哪里。如果AI应用是本地工具(比如开发者自己的对话助手),Server可以部署在本地,用stdio方式启动。如果AI应用是云端服务,Server需要部署在云端,用HTTP方式暴露。

对于Spring Boot服务,我推荐HTTP方式,因为Spring Boot的Web能力成熟,部署、监控、扩缩容都有现成方案。stdio方式虽然简单,但进程管理、日志收集、故障恢复都要自己搞,不适合生产环境。

部署时要注意:MCP Server应该和业务服务分开部署,不要混在同一个进程里。原因是MCP Server的流量特征和业务服务不同——AI应用的调用可能突发性很强,而且单个请求的耗时可能较长(因为模型决策需要时间)。分开部署可以独立扩缩容,避免互相影响。

5.2 超时与重试策略

MCP协议本身没有规定超时时间,但AI应用通常会有自己的超时设置。作为Server,你需要确保Tool的执行时间在合理范围内。如果一个Tool需要调用多个下游服务,总耗时可能超过AI应用的超时阈值,导致调用失败。

我的做法是:单个Tool的执行时间控制在3秒以内。如果某个操作天然耗时较长(比如批量导出),不要把它做成同步Tool,而是做成“提交任务”+“查询任务状态”两个Tool。第一个Tool立即返回任务ID,第二个Tool查询任务进度。这样每个Tool的响应都很快,模型也能给用户及时的反馈。

重试策略方面,MCP协议支持Client侧重试,但Server侧要做好幂等。如果一个Tool被重复调用(比如网络抖动导致Client重试),Server应该保证不会产生重复的业务影响。对于查询类Tool,天然幂等;对于写入类Tool,需要在Service层做幂等控制,比如用请求ID去重。

5.3 权限与安全

MCP Server暴露的是业务能力,权限控制不能省。基本的做法是在HTTP层做认证,比如用API Key或者OAuth。MCP协议本身不规定认证方式,但HTTP传输层可以复用标准的认证机制。

@Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/mcp/**").authenticated() .anyRequest().permitAll() ) .httpBasic(Customizer.withDefaults()); return http.build(); } }

除了认证,还要做授权。不同的AI应用可能只能访问部分Tool。比如客服助手只能查订单,不能改订单;运营助手可以改订单,但不能查用户隐私信息。这种细粒度的权限控制,建议在Tool方法里做,根据当前认证的身份判断是否有权调用。

安全提醒:MCP Server暴露的Tool可能包含敏感操作(比如退款、删除数据)。一定要确保只有经过认证和授权的AI应用才能调用这些Tool。不要因为“反正是内部服务”就省略认证。

5.4 监控与日志

生产环境必须要有监控。MCP Server的监控指标包括:每个Tool的调用次数、成功率、平均耗时、错误分布。这些指标可以用Micrometer + Prometheus + Grafana的标准方案采集和展示。

日志方面,每个Tool调用都应该记录:调用时间、调用方身份、Tool名称、输入参数(脱敏后)、返回结果摘要、耗时、是否成功。这些日志在排查问题时非常有用,尤其是当模型决策异常时,可以通过日志回溯模型到底调用了什么、传了什么参数。

@Around("@annotation(tool)") public Object logToolCall(ProceedingJoinPoint joinPoint, Tool tool) throws Throwable { long start = System.currentTimeMillis(); try { Object result = joinPoint.proceed(); log.info("Tool {} called, args={}, duration={}ms", tool.name(), sanitize(joinPoint.getArgs()), System.currentTimeMillis() - start); return result; } catch (Exception e) { log.error("Tool {} failed, args={}, error={}", tool.name(), sanitize(joinPoint.getArgs()), e.getMessage()); throw e; } }

这个切面可以统一处理日志,避免在每个Tool方法里写重复的日志代码。注意输入参数要脱敏,不要把密码、token之类的敏感信息记到日志里。

6. 常见问题排查速查表

问题现象可能原因排查方法解决方案
Inspector连接失败传输层配置错误检查端口、路径、协议类型确认Server启动日志中的MCP端点地址
Tools列表为空Tool未被扫描到检查@Component和@Tool注解确认包扫描路径包含Tool类
调用返回参数绑定失败参数名不一致对比Schema和DTO字段名统一用@JsonProperty标注
模型不调用Tool描述太模糊查看Schema中的description重写描述,写清楚用途和参数含义
调用超时Tool执行太慢查看Tool耗时日志拆分长耗时操作,或优化下游调用
返回结果模型无法理解返回结构太复杂检查返回JSON的字段数精简DTO,只返回必要字段
重复调用导致数据异常缺少幂等控制检查Service层是否有去重逻辑引入请求ID,做幂等处理
认证失败认证配置不匹配检查Client和Server的认证方式统一认证协议,确认密钥正确

这张表覆盖了我实际项目中遇到的大部分问题。排查时建议按顺序来:先确认连接是否正常,再确认Tool是否注册,再确认参数是否匹配,最后才怀疑模型决策。大部分问题都在前三步。

独家技巧:如果模型不调用Tool,除了检查描述,还可以在系统提示里显式告诉模型“你可以使用get_order工具查询订单”。有时候模型需要一点提示才会想到用工具。另外,Tool的name要简洁明了,不要用get_order_by_id_v2这种名字,模型对简洁的名字理解更好。

7. 从单个Tool到工具集的演进思路

7.1 工具分组与命名规范

当Tool数量超过10个时,命名规范就很重要了。我习惯用“领域_动作”的格式,比如order_get、order_update、user_query、user_disable。这样模型能快速理解Tool的归属和用途。

如果Tool特别多,可以考虑分组暴露。比如订单相关的Tool放在一个MCP Server里,用户相关的放在另一个。AI应用可以同时连接多个MCP Server,按需调用。这种拆分方式也便于权限控制——客服助手只连接订单Server,不连接用户Server。

7.2 组合Tool与工作流

有些业务操作需要多个步骤,比如“退款”需要先查订单、再校验状态、再发起退款、再通知用户。如果把这些步骤都暴露成独立的Tool,模型需要自己编排调用顺序,容易出错。

更好的做法是提供一个组合Tool,内部完成所有步骤,对外只暴露一个refund_order。模型只需要调用一次,传订单ID和退款原因,剩下的交给Server处理。这样既减少了模型的决策负担,也保证了业务逻辑的一致性。

当然,组合Tool的粒度要把握好。太细会导致模型编排困难,太粗会失去灵活性。我的经验是:如果一个操作在业务上是一个原子操作,就做成一个Tool。退款就是一个原子操作,不应该拆成四个Tool。

7.3 版本管理与兼容性

Tool的Schema可能会变化,比如新增参数、修改参数类型。这时候要考虑兼容性。如果直接改Schema,已经接入的AI应用可能会调用失败。

我的做法是:新增参数用可选,不删旧参数,不改参数类型。如果必须做破坏性变更,就新增一个Tool,名字加版本后缀,比如order_get_v2,旧Tool保留一段时间,等所有AI应用迁移后再下线。

MCP协议本身没有版本协商机制,所以兼容性要靠Server侧自己保证。这一点在多人协作的项目里尤其重要,改Tool Schema之前一定要通知所有接入方。

8. 我踩过的几个印象深刻的坑

第一个坑是Tool返回值序列化失败。有个Tool返回了一个包含LocalDateTime的对象,Jackson默认序列化成数组格式,模型看不懂。后来加了@JsonFormat注解,指定日期格式为ISO 8601字符串,问题才解决。教训是:所有返回给模型的字段,都要考虑序列化后的可读性。

第二个坑是Tool描述里的示例参数被模型当成真实参数。我在描述里写“例如order_id=123”,结果模型真的传了123,而不是用户实际要查的订单ID。后来把示例改成“订单ID,纯数字”,去掉了具体数值,问题消失。教训是:描述里不要放具体的示例值,只描述格式和含义。

第三个坑是并发调用导致的数据竞争。两个AI应用同时调用同一个写入Tool,导致数据不一致。后来在Service层加了乐观锁,并在Tool层面做了幂等控制,问题解决。教训是:MCP Server是无状态的,但业务逻辑可能是有状态的,并发控制不能省。

第四个坑是日志里记录了敏感信息。有个Tool的输入参数包含用户手机号,日志切面直接把参数打印出来了,导致手机号泄露到日志系统。后来加了脱敏逻辑,对手机号、身份证号、银行卡号等字段做掩码处理。教训是:日志脱敏要从第一天就做,不要等出事再补。

这些坑的共同点是:它们都不是MCP协议本身的问题,而是把业务逻辑暴露给AI时产生的工程问题。MCP解决了协议标准化的问题,但工程上的细节还是要靠开发者自己把控。

9. 后续可以扩展的方向

如果你已经跑通了单个Tool的接入,下一步可以考虑几个方向。

第一个方向是动态Tool注册。目前Tool是在代码里静态定义的,如果业务方想在不重启服务的情况下新增Tool,可以做一个管理界面,把Tool的定义存到数据库,运行时动态加载。这对多租户场景特别有用,不同租户可以有不同的Tool集。

第二个方向是Tool调用链追踪。当一个业务操作涉及多个Tool调用时,追踪整个调用链有助于排查问题。可以在MCP协议之上加一层Trace ID,贯穿所有Tool调用,日志和监控都带上这个ID。

第三个方向是Tool性能优化。对于高频调用的Tool,可以加缓存、加连接池、加异步处理。MCP协议本身不限制这些优化,Server侧可以自由发挥。

第四个方向是多协议适配。虽然MCP是标准,但现实中可能有些AI应用不支持MCP。可以在Server侧加一层适配,同时暴露MCP和自定义HTTP接口,让不同AI应用各取所需。适配层的成本不高,但能扩大服务的适用范围。

我个人在实际操作中的体会是:MCP的价值不在于协议本身有多复杂,而在于它让“业务服务”和“AI应用”之间的边界变得清晰。Server只管暴露能力,Client只管调用能力,中间的协议由MCP保证。这种清晰的边界,让后端团队和AI团队可以并行开发,互不阻塞。如果你手上有现成的Spring Boot服务,花半天时间把它接入MCP,后续的AI能力扩展会顺畅很多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进