Spring AI MCP Client 实战:让 Java 后端通过 stdio 调用本地工具服务

Spring AI MCP Client 实战:让 Java 后端通过 stdio 调用本地工具服务

摘要:本文用一个最小可落地的 Spring Boot 示例,讲清楚 Java 后端如何通过 Spring AI MCP Client 以 stdio 方式连接本地 MCP 工具服务。适合已经了解 Spring Boot,但还没把 MCP 真正接入 Java 项目的后端工程师。读完后你会知道依赖怎么加、配置怎么写、stdio server 怎么启动、工具如何暴露给 ChatClient,以及生产落地时最容易踩的超时、路径、进程和 Windows 命令包装问题。

验证状态说明:本文配置结构来自 Spring AI 官方 MCP Client Boot Starter 文档;代码为可落地的最小示例,需要根据你的 Spring AI 版本和模型供应商配置做本地回归。本文不使用公司内部日志或真实生产故障,所有日志均为模拟说明。

1. 为什么 Java 后端要关心 MCP Client

MCP(Model Context Protocol)可以把"外部工具能力"标准化暴露给大模型或 Agent。对 Java 后端来说,它最直接的价值不是概念,而是把已有系统能力接到 AI 应用里:

  • 本地文件、脚本、知识库、搜索、工单、监控查询可以作为工具服务;
  • Spring Boot 应用不用把所有工具逻辑写死在一个服务里;
  • 工具服务可以独立进程运行,Java 侧只做连接、发现和调用;
  • 后续可以从 stdio 平滑演进到 SSE / Streamable HTTP 这类远程传输方式。

在 Spring AI 里,MCP Client Boot Starter 已经提供了比较完整的自动配置能力:它可以管理多个 MCP client,支持 STDIO、SSE、Streamable HTTP 等连接方式,并能把 MCP 工具集成到 Spring AI 的 tool execution framework 中。

本文先讲最容易本地验证的 stdio 模式。

2. 整体调用链路

stdio 模式可以理解为:Spring Boot 启动时拉起一个本地子进程,这个子进程就是 MCP Server;双方通过标准输入输出交换 MCP 消息。

复制代码
用户请求
  -> Spring Boot Controller / Service
  -> ChatClient
  -> Spring AI Tool Callback
  -> MCP Client
  -> stdio transport
  -> 本地 MCP Server 进程
  -> 工具执行结果
  -> 模型综合回答

和 HTTP 调用不同,stdio 的关键点在"进程生命周期"和"标准输入输出协议"。你的 Java 服务不仅要会调用工具,还要能正确启动、关闭、超时和观测这个本地工具进程。

3. 环境和依赖

本文示例环境建议如下:

项目 建议版本 / 说明
JDK 17 或 21
Spring Boot 3.x
Spring AI 选择与你项目兼容的 1.x 版本
构建工具 Maven / Gradle 均可
MCP Server 本地可执行命令,例如 npx、node、python、Java jar
传输方式 stdio

Maven 依赖示例:

复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

如果你使用 Spring AI BOM,版本通常放在 dependencyManagement 中统一管理:

复制代码
<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>

注意:Spring AI 版本更新较快,正式项目里不要只复制依赖名,先对照你当前版本的官方文档确认 artifact、BOM 版本和模型 starter 名称。

4. 用 application.yml 配置 stdio MCP Server

Spring AI 官方文档中,stdio 相关配置前缀是:

复制代码
spring.ai.mcp.client.stdio

最小配置可以写成这样:

复制代码
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4o-mini
    mcp:
      client:
        enabled: true
        name: spring-ai-mcp-client
        version: 1.0.0
        initialized: true
        request-timeout: 20s
        type: SYNC
        toolcallback:
          enabled: true
        stdio:
          connections:
            filesystem:
              command: npx
              args:
                - -y
                - "@modelcontextprotocol/server-filesystem"
                - "./workspace"

这段配置做了几件事:

  1. 启用 MCP Client;
  2. 使用同步 client,也就是 type: SYNC
  3. 开启 MCP 工具到 Spring AI Tool Callback 的集成;
  4. 定义一个名为 filesystem 的 stdio 连接;
  5. 通过 npx -y @modelcontextprotocol/server-filesystem ./workspace 启动一个本地文件系统 MCP Server。

实际项目里你可以把 filesystem 换成自己的工具服务,例如:

复制代码
spring:
  ai:
    mcp:
      client:
        stdio:
          connections:
            order-tool:
              command: java
              args:
                - -jar
                - ./tools/order-mcp-server.jar
              env:
                APP_ENV: dev
                LOG_LEVEL: info

这里的 env 会作为 MCP Server 子进程的环境变量传入,适合放非敏感运行参数。敏感信息仍建议走密钥管理或环境变量注入,不要直接提交到 Git。

5. 使用外部 mcp-servers.json

如果你已经用过 Claude Desktop 或其他 MCP 客户端,也可以使用类似的 JSON 配置文件。

application.yml

复制代码
spring:
  ai:
    mcp:
      client:
        stdio:
          servers-configuration: classpath:mcp-servers.json

src/main/resources/mcp-servers.json

复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "./workspace"
      ]
    }
  }
}

这种方式的好处是跨客户端复用配置,坏处是 Java 项目中的环境差异更容易被忽略,比如工作目录、相对路径、Windows 命令包装等。

6. 在 ChatClient 里使用 MCP 工具

开启 spring.ai.mcp.client.toolcallback.enabled=true 后,Spring AI 可以把 MCP Server 暴露出来的工具接入 tool callback 体系。

一个典型 Service 可以这样写:

java 复制代码
`package com.example.demo.ai;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

@Service
public class McpChatService {

    private final ChatClient chatClient;

    public McpChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    public String ask(String question) {
        return chatClient.prompt()
                .system("你是一个 Java 项目助手。需要读取本地项目文件时,优先使用已接入的 MCP 工具。")
                .user(question)
                .call()
                .content();
    }
}
`

Controller 示例:

java 复制代码
`package com.example.demo.web;

import com.example.demo.ai.McpChatService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class McpDemoController {

    private final McpChatService mcpChatService;

    public McpDemoController(McpChatService mcpChatService) {
        this.mcpChatService = mcpChatService;
    }

    @GetMapping("/ai/ask")
    public String ask(@RequestParam String q) {
        return mcpChatService.ask(q);
    }
}
`

启动后可以用 curl 验证:

复制代码
curl "http://localhost:8080/ai/ask?q=请读取 workspace 目录下的 README.md 并总结"

预期现象是:模型在需要文件内容时,会触发 MCP filesystem 工具调用,再基于工具返回内容组织答案。

7. 启动和验证日志应该看什么

第一次接入时,不要上来就调业务接口,先看启动日志和 MCP client 初始化状态。

你应该重点确认三类信息:

模拟日志示例:

复制代码
INFO  o.s.ai.mcp.client - Creating MCP stdio connection: filesystem
INFO  o.s.ai.mcp.client - Starting MCP server command: npx -y @modelcontextprotocol/server-filesystem ./workspace
INFO  o.s.ai.mcp.client - MCP client initialized: filesystem
INFO  o.s.ai.tool - Registered MCP tools: filesystem.read_file, filesystem.list_directory

如果工具服务启动失败,常见日志会接近下面这样:

复制代码
ERROR o.s.ai.mcp.client - Failed to start MCP stdio server: filesystem
java.io.IOException: Cannot run program "npx": error=2, No such file or directory

这类问题通常不是 Spring AI 本身的问题,而是运行环境找不到命令。解决方向:

  • 用绝对路径指定 command;
  • 确认启动 Spring Boot 的用户能执行该命令;
  • 在 systemd、Docker、IDEA 三种运行方式下分别检查 PATH;
  • Node / Python / Java 工具服务尽量明确版本和路径。

8. Windows 下最容易踩的 cmd.exe 包装问题

Spring AI 官方文档专门提醒过 Windows stdio 配置:npxnpmnodepython 等在 Windows 上可能是 .cmd 批处理文件,而 Java ProcessBuilder 不能像 shell 一样直接执行这些批处理命令。

Windows 下建议写成:

复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "cmd.exe",
      "args": [
        "/c",
        "npx",
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "C:\\Users\\jerry\\workspace"
      ]
    }
  }
}

Linux / macOS 则可以直接:

复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "./workspace"
      ]
    }
  }
}

如果你的团队同时支持 Windows 和 Linux,建议在配置层做区分,或者用代码按 OS 生成 ServerParameters,不要把 Windows 的命令写法硬塞给所有环境。

9. 生产落地时的 6 个边界

stdio 模式适合本地工具和单机 sidecar,但不等于生产里可以随便拉进程。下面几个点建议在上线前确认。

9.1 工具进程生命周期

Spring Boot 应用重启时,MCP Server 子进程要能跟着关闭。否则很容易出现旧进程占资源、新进程连不上、工具状态错乱。

检查点:

复制代码
- 应用停止后,MCP Server 子进程是否退出
- 重启应用时是否会残留多个 server
- Docker / systemd 下 SIGTERM 是否能传递到子进程

9.2 请求超时

官方配置里有 spring.ai.mcp.client.request-timeout。不要使用无限等待。

建议:

复制代码
spring:
  ai:
    mcp:
      client:
        request-timeout: 10s

如果工具本身可能执行慢任务,把慢任务改成异步任务 ID + 查询结果,而不是让一次工具调用卡住整个模型请求。

9.3 工具权限

MCP Server 能访问什么目录、什么接口、什么命令,要明确限制。filesystem 这类工具尤其要注意:

复制代码
不要把 /、/home、生产配置目录、密钥目录直接暴露给 MCP 工具。

更合理的方式是只暴露一个工作目录,例如:

复制代码
./workspace

9.4 工具命名冲突

多个 MCP Server 同时接入时,工具名可能冲突。Spring AI MCP Client 支持工具过滤和工具名前缀生成相关能力,实际项目里应给不同 server 使用清晰命名,例如:

复制代码
filesystem.read_file
ticket.query_ticket
metrics.query_prometheus

9.5 可观测性

至少记录三类日志:

复制代码
- MCP Server 启动命令和连接名,不记录密钥
- 工具调用耗时、成功/失败、错误类型
- 模型请求和工具调用的 traceId

不要把完整 prompt、用户隐私、文件内容和密钥直接打进日志。

9.6 从 stdio 演进到远程传输

stdio 更适合本地 demo、开发工具、sidecar。团队化和多实例部署时,SSE / Streamable HTTP 往往更好治理:

维度 stdio SSE / Streamable HTTP
部署方式 跟应用同机子进程 独立服务
调试成本 本地简单,线上进程问题较多 网络链路更清晰
扩展性 适合单实例或 sidecar 适合多应用复用
权限控制 依赖本机进程权限 可加网关、鉴权、限流
适用场景 本地工具、脚本、文件系统 团队工具平台、共享能力

10. 一个更工程化的配置样例

下面是一个稍微完整一点的配置,适合放到开发环境验证:

复制代码
server:
  port: 8080

spring:
  application:
    name: spring-ai-mcp-client-demo
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4o-mini
    mcp:
      client:
        enabled: true
        name: ${spring.application.name}
        version: 1.0.0
        initialized: true
        request-timeout: 10s
        type: SYNC
        toolcallback:
          enabled: true
        stdio:
          connections:
            filesystem:
              command: npx
              args:
                - -y
                - "@modelcontextprotocol/server-filesystem"
                - "./workspace"
              env:
                NODE_ENV: development

logging:
  level:
    org.springframework.ai: INFO
    org.springframework.ai.mcp: DEBUG

本地验证步骤:

复制代码
mkdir -p workspace
printf "hello mcp from spring boot\n" > workspace/README.md

./mvnw spring-boot:run

curl "http://localhost:8080/ai/ask?q=读取 README.md,然后用一句话总结"

如果你没有配置可用的大模型供应商,MCP client 仍可能初始化成功,但 ChatClient 调用会失败。排查时要分清楚两层:

复制代码
MCP Server 是否启动成功
模型调用是否成功

不要把模型 API Key 问题误判成 MCP 配置问题。

11. 常见问题排查清单

现象 可能原因 排查方式
Cannot run program "npx" PATH 中没有 npx 使用绝对路径;检查运行用户环境变量
Windows 下启动失败 .cmd 不能被 ProcessBuilder 直接执行 cmd.exe /c npx ... 包装
应用启动卡住 MCP Server 启动后没有按协议响应 单独运行 server 命令;检查 stdout/stderr
工具列表为空 toolcallback 未启用或 server 未暴露工具 检查 toolcallback.enabled 和 server 日志
调用超时 工具执行慢或模型等待工具结果 缩短 request-timeout;给工具加超时和降级
本地可用,Docker 不可用 容器里没有 npx/node/文件路径 在镜像中安装依赖;改用绝对路径或挂载目录
工具能读到敏感文件 暴露目录过大 只暴露工作目录;加白名单和权限控制

12. 总结

Spring AI MCP Client 的价值在于:Java 后端不需要自己发明一套工具调用协议,就可以把本地工具、脚本和外部能力接到 AI 应用里。stdio 模式非常适合做第一版验证,因为它配置少、反馈快,也容易用本地文件系统或脚本服务跑通闭环。

但如果要进入生产环境,重点就不再是"能不能调通",而是:工具进程是否可控、权限是否收敛、超时是否明确、日志是否可观测、不同操作系统下启动命令是否一致。尤其是 Windows 的 cmd.exe /c 包装、Docker 中的 PATH、MCP Server 子进程残留,这些都是 Java 后端接 stdio 工具服务时最容易忽略的地方。

如果你关注 Java 后端、Spring Boot、Spring AI、MCP/Agent 落地和线上问题排查,可以关注我的 CSDN 专栏,后面会继续拆更工程化的 Java AI 应用实践。

相关推荐
plainGeekDev1 小时前
文件读写(Java IO)→ Kotlin 扩展函数
android·java·kotlin
Full Stack Developme1 小时前
AspectJ 详解
java·后端
元宝骑士1 小时前
SpringBoot + Sa-Token 实现浏览器级 CSRF 防御(基础篇)
spring boot·安全
武子康1 小时前
Java-20 深入浅出 MyBatis - 手写ORM框架1 从原始 JDBC 暴露的 6 大问题开始
java·后端
李燚2 小时前
Eino 的数据是怎么建模的:Message、ToolCall、流式管道
aigc·agent·ai编程·开发框架·agent框架
qq_2518364572 小时前
2026计算机毕设选题|3000套高质量SpringBoot实战项目(含完整源码)(每人一套不收米)
java·spring boot·课程设计
设计师小聂!2 小时前
Java异常处理
java·开发语言·后端·编辑器·idea
SimonKing2 小时前
实用,DynamicTP进阶之数据采集与告警
java·后端·程序员
用户298698530142 小时前
Java 进阶:基于模板生成 Word 文档的实践思路
java·后端