news 2026/9/28 19:35:05

Spring AI 1.x 系列【44】流式 HTTP 类型 MCP 服务端接入 TaoToken 配置实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 1.x 系列【44】流式 HTTP 类型 MCP 服务端接入 TaoToken 配置实战

1. 为什么要在 Spring AI 里折腾 Streamable HTTP 类型的 MCP 服务端

如果你正在用 Spring AI 1.x 做智能体或者工具调用相关的服务,大概率已经听过 MCP(Model Context Protocol)这个词。简单说,MCP 就是一套让「模型」和「外部工具/资源」之间用统一协议对话的规范。以前我们写工具调用,每个模型厂商的格式都不一样,换一个模型就得改一遍代码;有了 MCP,工具端只要按协议暴露能力,客户端按协议调用,模型侧换谁都能接。

而 Streamable HTTP 是 MCP 协议在 2025-03-26 版本里正式引入的传输方式,它取代了早期的 SSE 传输。它最大的特点是:MCP 服务端可以作为一个独立的 HTTP 进程跑起来,客户端通过 POST/GET 请求跟它交互,需要推送多条消息时再走 SSE 流式通道。这意味着你可以把「工具服务」和「模型调用」拆成两个独立部署的单元,服务端统一管理工具、资源、提示词,客户端只管连上来用。

这篇要解决的问题很具体:在 Spring AI 1.x 里,把 MCP 服务端配成 Streamable HTTP 类型,同时让服务端里所有需要调用大模型的地方,统一走 TaoToken 的 Key/API 通道。适合谁?适合那些不想在每个业务模块里散落一堆模型 Key、希望服务端集中管理模型调用出口的开发者。我会给出可复制的application.yml、MCP 服务端骨架、启动日志,以及怎么验证流式响应真的通了。

2. 前置准备:TaoToken 通道与依赖选型

在动手写配置之前,先把两件事定下来:模型调用通道用谁,以及 MCP 服务端用哪个 starter。

模型调用通道这块,我选的是 TaoToken。它的定位是统一的模型 API 入口,你拿到一个 Key,就能在服务端统一配置模型调用,不用在代码里到处硬编码不同厂商的地址和密钥。对 MCP 服务端这种「工具里可能还要调模型」的场景特别合适——工具执行逻辑里如果需要模型补全,直接复用同一套通道配置就行。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end ,API 入口是 https://taotoken.net/api ,注意 API 地址后面不加任何参数。

依赖选型上,Spring AI 1.x 提供了两个 Streamable HTTP 的 starter:

starter底层适用场景
spring-ai-starter-mcp-server-webmvcSpring MVC传统阻塞式,团队熟悉 MVC 的优先
spring-ai-starter-mcp-server-webfluxWebFlux响应式、非阻塞、连接数高的场景

两者能力基本对齐,都支持工具、资源、提示词、补全、日志、进度、心跳、根路径变更。区别只在底层线程模型。我下面用 WebMVC 版本演示,因为大多数 Spring Boot 项目本来就是 MVC 栈,迁移成本最低;如果你项目已经是 WebFlux,把依赖名换掉即可,配置项完全一样。

依赖这样引:

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

版本跟随你项目里的 Spring AI BOM,1.x 系列即可。引进来之后,MCP 服务端的自动配置就生效了,接下来全靠application.yml控制行为。

3. 可复制的 application.yml 与 MCP 服务端骨架

3.1 核心配置:protocol 必须设为 STREAMABLE

这是最容易踩的坑:不显式设置protocol: STREAMABLE,服务端不会按 Streamable HTTP 模式启动。默认值不是它。完整配置如下,可以直接抄:

server: port: 8080 spring: ai: mcp: server: enabled: true protocol: STREAMABLE name: streamable-mcp-server version: 1.0.0 type: SYNC instructions: "This streamable server provides real-time notifications" resource-change-notification: true tool-change-notification: true prompt-change-notification: true capabilities: tool: true resource: true prompt: true completion: true streamable-http: mcp-endpoint: /api/mcp keep-alive-interval: 30s

几个关键项解释一下。protocol: STREAMABLE是总开关,决定传输类型。type: SYNC表示同步服务端,工具处理器用McpSyncServerExchange;如果你的工具里有大量阻塞 IO 想改成异步,设成ASYNC,处理器换成McpAsyncServerExchange。mcp-endpoint: /api/mcp是客户端要连的路径,默认是/mcp,我改成/api/mcp是为了跟业务接口区分开。keep-alive-interval: 30s是保活心跳,默认禁用,开了之后服务端会定期给已连接的客户端发心跳,注意目前这个保活只对 SSE 那条「Listening for Messages from the Server」连接生效。

3.2 模型调用通道配置

MCP 服务端本身不强制你配模型,但工具执行逻辑里如果要调模型,就得有通道。把 TaoToken 的配置单独放一段,方便统一管理:

spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini

这里base-url指向 TaoToken 的 API 入口,api-key用环境变量注入,别写死在 yml 里。模型名按你实际开通的填。这样服务端里任何需要模型补全的地方,都走这一条通道,换模型只改这一处。

3.3 MCP 服务端骨架:工具 + 资源 + 提示词

光有配置不够,得有实际暴露的能力。下面是一个最小可用的服务端骨架,包含一个工具、一个资源、一个提示词:

@SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } @Bean public ToolCallbackProvider weatherTools(WeatherService weatherService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherService) .build(); } } @Service public class WeatherService { @Tool(description = "根据城市名称获取天气信息") public String getWeather(String cityName) { return "城市 " + cityName + " 当前晴,气温 22 摄氏度"; } }

@Tool注解的方法会被自动扫描并注册成 MCP 工具,ToolCallbackProvider这个 Bean 负责把工具对象转成 MCP 声明。自动配置会检测所有ToolCallback、ToolCallback列表、ToolCallbackProvider类型的 Bean,合并注册,重名工具以首次出现的为准。如果你想关掉自动转换,设spring.ai.mcp.server.tool-callback-converter=false。

资源注册用底层 API 长这样:

@Bean public List<McpServerFeatures.SyncResourceSpecification> myResources() { var systemInfoResource = new McpSchema.Resource( "system://info", "system-info", "系统信息", "application/json", null); var spec = new McpServerFeatures.SyncResourceSpecification( systemInfoResource, (exchange, request) -> { String json = "{\"os\":\"linux\",\"jdk\":\"21\"}"; return new McpSchema.ReadResourceResult( List.of(new McpSchema.TextResourceContents( request.uri(), "application/json", json))); }); return List.of(spec); }

提示词注册类似,用SyncPromptSpecification包一个McpSchema.Prompt加处理器即可。这三类能力默认全开,想关哪个就把capabilities下对应项设成false,服务端就不再注册和暴露它。

4. 启动验证与流式响应确认

4.1 看启动日志确认协议生效

启动应用后,日志里应该能看到 MCP 服务端初始化的痕迹。重点确认两件事:协议是 STREAMABLE,端点是/api/mcp。如果日志里出现类似Registered MCP tool(s)或者工具数量统计,说明工具注册成功。如果没看到任何 MCP 相关日志,八成是protocol没设对,或者 starter 没引进来。

4.2 用 curl 验证端点

先确认端点活着。Streamable HTTP 的交互是 POST 请求带 JSON-RPC 消息体:

curl -i -X POST http://localhost:8080/api/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": {"name": "curl-client", "version": "1.0"} } }'

注意Accept头必须同时包含application/json和text/event-stream,否则服务端可能拒绝。返回里应该能看到服务端的能力声明,包括 tools、resources、prompts 这些。

4.3 验证流式响应

初始化之后,调用工具并观察流式返回。用tools/call方法:

curl -N -X POST http://localhost:8080/api/mcp \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "getWeather", "arguments": {"cityName": "杭州"} } }'

-N关闭 curl 缓冲,这样你能实时看到 SSE 事件逐条推过来。如果返回里出现event: message加data:的格式,并且内容是工具执行结果,说明流式通道通了。这一步是判断 Streamable HTTP 是否真正工作的关键——普通 HTTP 一次性返回和 SSE 流式推送,行为完全不同。

5. 本篇常见错误排查

启动报错说找不到 MCP 端点或者 404:先检查mcp-endpoint配的路径和你 curl 的路径是否一致。默认是/mcp,我改成了/api/mcp,如果你抄配置时只抄了一半,很容易对不上。另外确认server.port没被其他配置覆盖。

客户端连上但工具列表为空:检查capabilities.tool是不是被设成了false,以及tool-callback-converter是不是被关了。还有一种情况是工具方法没加@Tool注解,或者ToolCallbackProviderBean 没被扫描到——确认它在@SpringBootApplication所在包或子包下。

流式响应收不到,只有一次性返回:检查请求头Accept是否包含text/event-stream。Streamable HTTP 服务端会根据 Accept 头决定用普通 JSON 还是 SSE 返回。另外keep-alive-interval只影响 SSE 长连接的心跳,不影响单次请求的流式行为,别把它当成流式开关。

模型调用报 401 或地址错误:检查base-url是不是https://taotoken.net/api,注意 API 地址后面不要带多余路径或参数。api-key确认环境变量注入成功,可以在启动日志里打印一下配置(别打印 Key 本身)。

保活心跳没生效:目前 Streamable HTTP 的保活只对 SSE 那条监听连接生效,普通 POST 请求不会触发。如果你期望每个请求都有心跳,那是理解偏差,不是配置问题。

6. 把通道和 Key 管起来

服务端跑通之后,下一步就是把模型调用的 Key 和通道真正管起来。TaoToken 的控制台可以创建和管理 API Key,建议按环境(开发/测试/生产)分开建 Key,别一个 Key 到处用。创建入口在 https://taotoken.net/api-keys ,接入文档在 https://taotoken.net/doc ,里面有各语言和框架的接入示例,Spring AI 的配置方式也能对上。

如果你后面要做长期编码任务或者 Agent 类的持续调用,可以看下 Coding Plan,它更适合高频、长周期的模型调用场景:https://taotoken.net/coding-plan 。想先在网页上直接验证模型通不通,用模型对话页面最快:https://taotoken.net/chat 。控制台总入口是 https://taotoken.net/console 。

我自己的习惯是:MCP 服务端里所有模型调用都走同一套base-url+ 环境变量 Key,工具逻辑里不出现任何硬编码密钥。这样换模型、换 Key、加环境,都只动配置不动代码。流式这块,先用 curl 把initialize和tools/call两步跑通,再去接客户端,能省掉一大半联调时间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 19:34:35

DMA与外存计算:从408真题看磁盘I/O综合题解法

备考408的过程里&#xff0c;计算机组成原理的I/O章节和外存计算&#xff0c;一直是很多人头疼的两个点。2022年那道44题把这两个知识点焊在了一起&#xff1a;一边是DMA方式&#xff0c;一边是磁道、扇区的计算。很多同学单独背DMA原理会背&#xff0c;单独算磁盘容量会算&…

作者头像 李华
网站建设 2026/9/28 19:33:30

面向多模态生成的流式图片渐进式加载与展卷动效

在多模态生成式 AI&#xff08;如 Midjourney、Stable Diffusion、DALL-E 3、FLUX&#xff09;交互中&#xff0c;生成一张 2K 高清图像往往需要经历数十步扩散迭代&#xff08;Diffusion Steps&#xff09;&#xff0c;耗时 3 ~ 8 秒。 如果前端只是展示一个生硬的转圈 Loadin…

作者头像 李华