☰
【MCP协议】Model Context Protocol深度解析——从原理到Spring AI实战配置TaoToken
2026/9/29 3:13:43 网站建设 项目流程

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

如果你最近在折腾 Agent 应用,大概率会碰到一个绕不开的词:MCP 协议。它的全称是 Model Context Protocol,中文一般叫模型上下文协议,由 Anthropic 在 2024 年底开源。简单说,它想干的事情就是给大模型和外部工具、数据源之间定一套统一的通信标准,让工具开发者写一次,所有兼容 MCP 的模型应用都能直接调用。

那它到底能做什么?打个比方,以前你给 GPT 写一套 Function Calling 的 JSON Schema,给 Claude 又要写一套 Tool Use 的定义,换到国产模型还得再适配一遍,工具代码和模型厂商死死绑在一起。MCP 的思路是把工具能力从 AI 应用里解耦出来,做成独立的 MCP Server,通过 JSON-RPC 2.0 通信,谁都能连。这跟当年 LSP 把语言能力从编辑器里拆出来是一个套路。

适合谁看?主要是 Java 后端开发者,尤其是已经在用 Spring Boot、准备把大模型能力接进业务系统的那批人。Spring AI 从 1.0.0 GA 开始正式支持 MCP,1.1.0-M3 又引入了注解式的 MCP Server 开发模型,写一个工具服务基本就是写几个带注解的 Spring Bean。这篇会从协议原理讲到 Spring AI 的落地配置,重点给出接入 TaoToken 统一 Key/API 通道的application.yml与settings.json骨架,并完整演示一次 MCP 工具调用链路的验证动作,确认协议握手和模型响应都正常。

我踩过的坑是:很多人一上来就纠结协议细节,结果配置卡在鉴权和 base-url 上。所以这篇的顺序是先讲清楚 MCP 的三方架构和三大能力,再动手配通道,最后跑通一次真实调用。

2. MCP 协议原理:三方架构与三大能力

2.1 Host、Client、Server 各管什么

MCP 采用经典的三方架构,把关注点拆得很干净。Host 是承载 LLM 的用户应用,比如 Claude Desktop、IDE 插件,或者你自己写的 AI 应用;Client 是协议通信端,由 Host 管理,和 Server 建立 1:1 连接,维护会话状态;Server 是提供具体工具能力的服务端,比如天气查询、数据库操作、文件系统访问。

关键设计原则有三条:Host 和 Server 之间不直接通信,所有消息都通过 Client 中转;一个 Host 可以管理多个 Client,连到不同的 MCP Server;一个 Server 也能接受多个 Client 的连接。通信格式统一走 JSON-RPC 2.0,当前协议版本是 mcp-2025-11-25。

2.2 Tools、Resources、Prompts 三大原语

MCP 定义了三种核心能力原语。Tools 是最常用的,对应 Function Calling 场景,Server 端定义可调用的函数,Client 端发现并调用,典型场景是天气查询、数据库 CRUD、API 调用。Resources 常被忽视但很重要,它是 Server 管理的、可通过 URI 寻址的数据资源,主要用于数据读取而非操作执行,比如配置管理、知识库文档。Prompts 是 MCP 的独特创新,允许 Server 维护一套可参数化的提示词模板,Client 按需获取,适合角色系统提示词库、工作流模板这类场景。

2.3 传输方式:STDIO 与 HTTP SSE

MCP 定义了两种传输机制。STDIO 走进程间通信,通过 stdin/stdout 交换消息,适合本地开发、桌面应用、IDE 插件,延迟最低但受限于单机。HTTP SSE 走 HTTP 长连接,适合分布式部署、微服务架构、云端连接,支持水平扩展和重连,但需要网络层安全措施。选型上,本地调试用 STDIO,生产环境用 HTTP SSE,这是比较稳妥的默认策略。

2.4 一次工具调用的完整链路

一次完整的 MCP 工具调用包含八个步骤:Host 启动并创建 Client,Client 发送 initialize 请求;Server 返回协议版本和能力;Client 发送 initialized 通知建立会话;Client 通过 tools/list 发现可用工具;用户在 Host 发起自然语言请求;Host 把请求和工具列表发给 LLM;LLM 决定调用哪个工具,Host 通过 Client 发送 tools/call;Server 执行并返回结果,LLM 生成最终响应。

这个流程里最关键的是能力发现:工具列表和 Schema 是动态获取的,Server 端新增工具或改参数,Client 端不用重新部署就能感知。

3. 前置准备:TaoToken 统一 Key 与 API 通道

在动手写 Spring AI 代码之前,先把模型通道配好。TaoToken 提供统一的 Key 和 API 通道,兼容 OpenAI 风格的接口,这样你的 MCP Client 在调用 LLM 做工具决策时,不用为每个模型厂商单独适配。

你需要先拿到一个 API Key。登录官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,进入控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 创建密钥,然后在 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 复制出来。API 的基础地址是 https://taotoken.net/api ,注意这个地址不带任何查询参数,配置时直接填。

如果你用的是 Claude Code 这类编码工具,可以参考接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 里的说明;如果是长期做编码和 Agent 开发,Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 会更划算。模型对话入口在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,可以先在网页上试一下模型是否正常响应,再去写代码。

注意:API Key 属于敏感凭证,不要硬编码进代码仓库,用环境变量或配置中心注入。

4. Spring AI 接入配置:application.yml 与 settings.json 骨架

4.1 Maven 依赖与 BOM 版本管理

先统一版本,用 Spring AI BOM 管理依赖,避免版本冲突。当前稳定版是 1.0.3,想用注解式 MCP Server 的话需要 1.1.0-M3 及以上。

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

然后按角色引入 Starter。做 Client 用spring-ai-starter-mcp-client,做 Server 用spring-ai-starter-mcp-server-webmvc(Servlet 架构)或spring-ai-starter-mcp-server-webflux(响应式架构)。

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

4.2 application.yml 完整骨架

下面是接入 TaoToken 统一通道的application.yml骨架。核心是把 OpenAI 兼容的 base-url 指向 TaoToken,api-key 从环境变量读取,同时配置 MCP Client 连接远程 Server。

server: port: 8080 spring: ai: openai: # TaoToken 统一 API 通道,注意不带查询参数 base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.7 mcp: client: # HTTP SSE 方式连接远程 MCP Server sse: connections: weather-server: url: http://localhost:8081/mcp # 也可同时用 STDIO 连接本地 Server stdio: connections: local-tools: command: java args: - "-jar" - "local-mcp-server.jar"

启动前设置环境变量:

export TAOTOKEN_API_KEY="你的Key"

4.3 settings.json 骨架(Claude Code / 客户端场景)

如果你在 Claude Code 或类似客户端里配置 MCP Server,通常会用到settings.json。下面是一个骨架,把模型通道指向 TaoToken,同时声明 MCP Server 的启动方式。

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "你的Key" }, "mcpServers": { "weather-server": { "url": "http://localhost:8081/mcp" }, "local-tools": { "command": "java", "args": ["-jar", "local-mcp-server.jar"] } } }

提示:ANTHROPIC_BASE_URL填 TaoToken 的 API 地址即可,不要带 UTM 参数,避免请求异常。

4.4 MCP Server 端注解式实现

Spring AI 1.1.0-M3 的注解模型让 Server 开发变得非常简洁。下面是一个天气 MCP Server,同时暴露 Tool、Resource、Prompt 三种能力。

@Service public class WeatherMcpServer { @McpTool(name = "getWeather", description = "获取指定城市的实时天气信息") public String getWeather( @McpToolParam(description = "城市名称", required = true) String cityName) { Map<String, String> weatherData = Map.of( "上海", "晴天, 气温25°C, 湿度65%", "北京", "多云, 气温22°C, 湿度40%", "深圳", "阵雨, 气温28°C, 湿度85%" ); return weatherData.getOrDefault(cityName, "暂无该城市天气数据"); } @McpResource(uri = "weather://config/{key}", name = "weather-configuration", description = "天气服务配置资源") public String getWeatherConfig(String key) { Map<String, String> configs = Map.of( "defaultCity", "上海", "updateInterval", "30min" ); return configs.getOrDefault(key, "配置项不存在: " + key); } @McpPrompt(name = "weather-analysis", description = "天气数据分析提示词模板") public McpSchema.GetPromptResult weatherAnalysisPrompt( @McpArg(name = "city", description = "要分析的城市") String city) { String systemPrompt = String.format( "你是一位专业的气象分析师。请根据%s的天气数据,提供当前状况、未来趋势和出行建议。", city); return new McpSchema.GetPromptResult( "WeatherAnalysis", List.of(new McpSchema.PromptMessage( McpSchema.Role.ASSISTANT, new McpSchema.TextContent(systemPrompt))) ); } }

Server 端的application.yml需要声明服务名和版本:

server: port: 8081 spring: ai: mcp: server: name: weather-mcp-server version: 1.0.0 annotation-scanner: enabled: true

5. 验证请求:跑通一次 MCP 工具调用链路

配置写完了,接下来验证协议握手和模型响应是否正常。分两步走:先确认 MCP Server 的能力发现,再跑一次完整的工具调用。

5.1 验证 MCP Server 能力发现

启动 Server 后,用 curl 发一个tools/list请求,确认工具列表能正常返回。这一步验证的是协议握手和能力协商。

curl -X POST http://localhost:8081/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }'

正常返回应该包含getWeather工具的名称、描述和参数 Schema。如果返回-32601 Method not found,说明注解扫描没生效,检查annotation-scanner.enabled是否为 true。

5.2 验证完整工具调用链路

在 Client 端写一个 Controller,把 MCP 工具注册进 ChatClient,然后发一句自然语言请求,观察 LLM 是否自动选择工具并返回结果。

@RestController public class McpClientController { private final ChatClient chatClient; private final ToolCallbackProvider toolCallbackProvider; public McpClientController(ChatClient.Builder chatClientBuilder, ToolCallbackProvider toolCallbackProvider) { this.chatClient = chatClientBuilder.build(); this.toolCallbackProvider = toolCallbackProvider; } @GetMapping("/chat") public String chat(@RequestParam String message) { return chatClient .prompt() .user(message) .toolCallbacks(toolCallbackProvider.getToolCallbacks()) .call() .content(); } }

启动 Client 后发请求:

curl "http://localhost:8080/chat?message=帮我查一下上海今天的天气"

预期结果是模型先调用getWeather工具,拿到「晴天, 气温25°C, 湿度65%」,再生成一句自然语言回复。如果模型直接编造天气而没有调用工具,说明工具回调没注册成功,检查ToolCallbackProvider是否被正确注入。

5.3 手动读取 Resource 和 Prompt

除了自动工具调用,也可以手动验证 Resource 和 Prompt 能力,确认三大原语都通。

@RestController public class McpCapabilityController { @Autowired private List<McpSyncClient> mcpSyncClients; @GetMapping("/mcpResource") public String readResource(@RequestParam String uri) { McpSyncClient client = mcpSyncClients.get(0); McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest(uri); McpSchema.ReadResourceResult result = client.readResource(request); return ((McpSchema.TextResourceContents) result.contents().get(0)).text(); } @GetMapping("/mcpPrompt") public String getPrompt(@RequestParam String name, @RequestParam String arg) { McpSyncClient client = mcpSyncClients.get(0); McpSchema.GetPromptRequest request = new McpSchema.GetPromptRequest(name, Map.of("city", arg), null); McpSchema.GetPromptResult result = client.getPrompt(request); return ((McpSchema.TextContent) result.messages().get(0).content()).text(); } }

访问http://localhost:8080/mcpResource?uri=weather://config/defaultCity应该返回「上海」,访问 Prompt 接口应该返回完整的提示词文本。这两个都通了,说明 MCP 的三大能力全部验证通过。

6. 本篇常见错误排查

6.1 连接被拒或 401 未授权

最常见的是 API Key 没配好。检查环境变量TAOTOKEN_API_KEY是否生效,base-url是否写成https://taotoken.net/api(不要带 UTM 参数,不要漏掉/api)。如果返回 401,去控制台确认 Key 是否被禁用或额度耗尽。

6.2 tools/list 返回空列表

注解扫描没生效。确认依赖是spring-ai-starter-mcp-server-webmvc或 webflux,annotation-scanner.enabled为 true,且@McpTool标注的方法所在的类被 Spring 扫描到(在启动类包路径下)。另外注意方法必须是 public。

6.3 模型不调用工具,直接编答案

工具回调没注册进 ChatClient。检查ToolCallbackProvider是否注入成功,.toolCallbacks(toolCallbackProvider.getToolCallbacks())是否真的传进去了。还有一种情况是模型本身对工具描述理解不到位,把@McpTool的 description 写清楚一点,参数说明也补全。

6.4 SSE 连接超时或断流

远程 MCP Server 的 SSE 连接对网络稳定性有要求。检查 Server 是否真的在监听/mcp路径,防火墙是否放行端口。如果是内网部署,确认 Client 能访问到 Server 地址。生产环境建议加 TLS 和重连机制。

6.5 版本不匹配导致注解不识别

@McpTool、@McpResource这些注解是 1.1.0-M3 才引入的。如果你用的是 1.0.3,注解不会生效,只能用编程式 API 手动注册工具。检查 BOM 版本,需要注解模型就升到 1.1.0-M3 及以上。

7. 继续深入的方向

跑通一次调用只是起点。接下来可以往几个方向走:把 MCP Server 部署成远程 SSE 服务,接入企业内网;用 MCP Gateway 统一管理多个 Server 的认证、限流和审计;把已有的 REST 接口通过协议转换包装成 MCP 工具,复用现有业务能力。

如果你在编码场景里长期用 Agent,可以看看 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,配合 Claude Code 的接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 把工具链串起来。遇到接入或排障问题,直接翻接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 和 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 基本都能解决。先把这篇的配置跑通,再往上叠复杂度,比一上来就啃协议细节要顺得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询