Spring AI 接入 MCP:DeepSeek 连接 Filesystem Server 读取本地文件
Spring AI 接入 MCP:DeepSeek 连接 Filesystem Server 读取本地文件
做 Tool Calling Demo 时,我们通常会把工具直接写在 Java 应用里:
@Tool(description="查询订单")publicStringqueryOrder(StringorderId){returnorderService.query(orderId);}这种写法很适合接入自己项目里的业务方法。
但如果工具来自外部系统,比如文件系统、GitHub、数据库、浏览器、运维平台,每个 AI 应用都重复写一套适配代码,就会很累。
MCP 要解决的就是这个问题:
外部工具怎么用统一协议接进 AI 应用。
它不是替代 Tool Calling,而是和 Tool Calling 配合:
Tool Calling:模型怎么请求调用工具 MCP:外部工具怎么标准化接进来这次只跑一条最小链路:
Spring AI 作为 MCP Client,连接本地 Filesystem MCP Server,让模型读取一个测试文件。
先把这条链路跑通,再去接 GitHub、数据库、浏览器这些 MCP Server,就不会乱。
注意:这篇只演示本地测试目录。生产环境不要随便把真实目录暴露给模型。
一、先把范围缩小
Spring AI 里和 MCP 相关的写法不止一种:
Spring AI 做 MCP Client Spring AI 做 MCP Server stdio 连接本地 MCP Server SSE / Streamable HTTP 连接远程 MCP Server入门时不要全塞在一起。我们先选最容易跑通的一条:
Spring AI 做 MCP Client,通过 stdio 连接本地 Filesystem MCP Server。
整体关系是这样:
Spring AI 应用 → 启动并连接 Filesystem MCP Server → 获取 Server 暴露的文件工具 → 把工具交给模型 → 模型通过 Tool Calling 请求调用 → MCP Server 真正读取文件简单说:
MCP Client:你的 Spring AI 应用 MCP Server:外部工具服务这篇用现成的 Filesystem Server,不从零写 Server。先把接入跑通。
二、准备一个测试目录
先准备几个前提:
- 你已经有一个能正常调用
ChatClient的 Spring Boot 项目; - 项目使用 Spring AI 1.1.7;
- 本机已经安装 Node.js 和
npx; - 当前模型支持 Tool Calling。
这篇示例使用 DeepSeek,模型用deepseek-v4-flash。如果你走的是第三方兼容网关,要确认网关会不会完整透传tools参数和 tool call 响应。
先建一个测试目录:
mkdir-p/tmp/spring-ai-mcp-demoecho"Hello from Spring AI MCP Demo">/tmp/spring-ai-mcp-demo/test.txt先手动验证 Filesystem MCP Server 能不能启动:
npx-y@modelcontextprotocol/server-filesystem /tmp/spring-ai-mcp-demo如果看到类似输出,说明本地 Server 能跑:
Secure MCP Filesystem Server running on stdio验证完可以停掉。真正接入 Spring AI 时,Spring AI 会根据配置自动启动它。
三、添加依赖
pom.xml至少需要这几个依赖:
<properties><java.version>17</java.version><spring-ai.version>1.1.7</spring-ai.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.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-deepseek</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client</artifactId></dependency></dependencies>spring-ai-starter-mcp-client负责把 Spring AI 应用变成 MCP Client。这篇连接的是本地 stdio Server。
如果以后要接远程 MCP Server,再考虑spring-ai-starter-mcp-client-webflux。
四、配置 DeepSeek 和 MCP
application.yaml这样写:
spring:application:name:spring-ai-mcp-demoai:model:chat:deepseekdeepseek:api-key:${DEEPSEEK_API_KEY}chat:options:model:deepseek-v4-flashtemperature:0.2mcp:client:type:SYNCstdio:connections:filesystem:command:npxargs:--y-"@modelcontextprotocol/server-filesystem"-/tmp/spring-ai-mcp-demo启动前设置环境变量:
exportDEEPSEEK_API_KEY=你的 API Key这段配置的关键点有三个:
- 使用 DeepSeek 作为聊天模型;
- 通过
npx启动 Filesystem MCP Server; - 只暴露
/tmp/spring-ai-mcp-demo测试目录。
如果用 IDEA 运行,在 Run/Debug Configurations 里给启动配置加环境变量:
DEEPSEEK_API_KEY=你的 API KeyWindows 上通常要用cmd.exe /c包一层:
command:cmd.exeargs:-/c-npx--y-"@modelcontextprotocol/server-filesystem"-C:\tmp\spring-ai-mcp-demomacOS / Linux 按前面的写法即可。
五、写一个测试接口
新建McpController:
packagecom.example.springaideepseekdemo.controller;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.tool.ToolCallbackProvider;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassMcpController{privatefinalChatClientchatClient;privatefinalToolCallbackProvidermcpTools;publicMcpController(ChatClient.Builderbuilder,ToolCallbackProvidermcpTools){this.chatClient=builder.defaultSystem(""" 你是一个文件读取助手。 只能通过工具访问 /tmp/spring-ai-mcp-demo 目录。 当用户说 test.txt 或测试目录时,都指 /tmp/spring-ai-mcp-demo。 不要请求访问 /、用户主目录、项目源码目录或其他目录。 """).build();this.mcpTools=mcpTools;}@GetMapping("/ask")publicStringask(@RequestParamStringquestion){returnchatClient.prompt().user(question).toolCallbacks(mcpTools).call().content();}}这里有个容易写错的点:不要想当然写成McpClient.getTools("filesystem")。
在 Spring AI 1.1.7 里,MCP Client Starter 会把 MCP Server 暴露的工具转换成ToolCallbackProvider。
ChatClient可以直接这样接:
.toolCallbacks(mcpTools)如果项目里还有其他ToolCallbackProviderBean,构造方法注入时可能需要用@Qualifier指定。这个最小 Demo 只有一个 MCP Provider,可以直接注入。
六、启动测试
启动应用:
./mvnw spring-boot:run读取test.txt:
curl--get"http://localhost:8080/ask"\--data-urlencode"question=帮我读取 /tmp/spring-ai-mcp-demo/test.txt 的内容"如果模型选择了文件读取工具,最终会返回类似:
test.txt 的内容是:Hello from Spring AI MCP Demo也可以测试列目录:
curl--get"http://localhost:8080/ask"\--data-urlencode"question=列出 /tmp/spring-ai-mcp-demo 目录下有哪些文件"如果日志里出现:
Access denied - path outside allowed directories不用慌。
这说明模型请求了白名单之外的路径,比如/。Filesystem MCP Server 拒绝了这次访问,这是安全拦截,不是 MCP 没接上。
如果模型一直普通回答,没有请求工具,优先检查:
模型是否支持 Tool Calling DEEPSEEK_API_KEY 是否正确 中间网关是否透传 tools 参数先跑编译:
./mvnw clean compile-DskipTests然后启动应用,请求/ask,能读到:
Hello from Spring AI MCP Demo七、背后发生了什么
业务代码看起来只有这一段:
chatClient.prompt().user(question).toolCallbacks(mcpTools).call().content();背后其实分成两条链路。
应用启动时:
Spring AI 读取 application.yaml → 启动 Filesystem MCP Server → 建立 stdio 连接 → 获取 Server 的工具列表 → 转成 Spring AI 的 ToolCallback用户提问时:
用户提问 → 模型看到可用工具 → 模型判断要调用文件工具 → Spring AI 执行 ToolCallback → ToolCallback 通过 MCP 调用 Filesystem Server → Server 读取文件并返回结果 → 模型基于工具结果组织回答所以 MCP 和 Tool Calling 不是两套互斥方案:
MCP 负责把外部工具接进来 Tool Calling 负责让模型请求调用这些工具八、什么时候用 MCP
如果只是当前项目里的几个业务方法,直接写@Tool更轻:
查订单 查物流 查库存这些能力本来就在当前应用里,没必要为了 MCP 多绕一层。
MCP 更适合:
工具要被多个 AI 应用复用 工具需要独立部署和维护 要接入现成的外部 MCP Server 工具很多,不想每个应用都重复适配可以这样记:
@Tool:把当前应用里的方法暴露给模型 MCP:把外部工具服务标准化接入应用Spring AI 不需要知道 Filesystem Server 内部怎么读文件,只要按 MCP 协议连接它、拿到工具、执行工具调用就行。
九、别忽略安全边界
MCP 接入不难,但安全边界一定要提前想清楚。Filesystem Server 会真正读写文件。
入门 Demo 只暴露:
/tmp/spring-ai-mcp-demo不要暴露:
/ /Users/你的用户名 项目源码目录 .ssh 配置和密钥目录工具描述不是权限控制。真正的目录边界、权限校验、危险操作拦截,都要在应用侧或 MCP Server 侧做。
入门阶段建议只读文件、列目录。
如果要开放写入、创建目录、移动文件,至少要加:
用户权限校验 目录白名单 操作日志 二次确认 限流和超时还有一个常见误区:MCP Server 能连上,不代表模型一定会调用工具。
模型会不会调用,还取决于模型能力、工具描述、用户问题,以及模型服务是否支持 Tool Calling。
排查时分两步看:
先确认 MCP Server 能启动 再确认模型真的返回 tool call这两个问题不要混在一起。
写在最后
这篇文章跑通的是一条最小链路:
Filesystem MCP Server 暴露工具 → Spring AI MCP Client 连接 Server → MCP 工具转成 ToolCallbackProvider → ChatClient 把工具交给模型 → 模型通过 Tool Calling 请求调用 → Spring AI 通过 MCP 执行工具如果说@Tool是把工具写在应用里,那 MCP 就是把工具从应用里拆出去,再用协议接回来。
它的价值不在于“更高级”,而在于:
- 工具可以独立维护;
- 多个 AI 应用可以复用;
- 外部工具生态可以标准化接入。
但 MCP 只负责连接,不负责替你做权限、业务规则和风险兜底。
先用本地 Filesystem Server 跑通,再考虑 GitHub、数据库、浏览器或公司内部系统。
Agent 能力越多,安全边界越要清楚。
后续会继续更新 Spring AI、RAG、Memory、Tool Calling、MCP 等实战内容。
