目录:
- 一、为什么需要 MCP?
- 二、MCP 的两种通信方式
- 三、STDIO 方式详解
- 1. MCP Server(服务端)
- ① 使用现成的公共 MCP Server
- ② 自定义 STDIO MCP Server
- 2. MCP Client(客户端)调用 STDIO
- 3. STDIO 方式鉴权
- 四、SSE 方式详解
- 1. MCP Server(服务端)
- 2. MCP Client(客户端)
- 3. SSE 方式鉴权(OAuth2)
一、为什么需要 MCP?
在 AI 应用爆发式增长的今天,我们常常面临两个痛点:
- 服务商想开放工具:比如高德地图提供位置查询、百度提供联网搜索,但每个服务商都有自己的 API 格式,调用方式千差万别。
- 企业内部多应用共享工具:多个智能应用都想使用同一套内部工具(如订单查询、用户画像),如果每个应用各自接入,重复造轮子且维护成本极高。
解决方案很简单:把 Tools 单独抽取出来,由应用程序统一读取外部 Tools。
但问题随之而来——怎么读?怎么解析?
如果每个提供商各用一套规则,想象一下对接几十个不同 API 的混乱场面……
于是MCP(Model Context Protocol)应运而生。
MCP 指定了 标准通信规则,以JSON‑RPC 2.0格式进行交互,彻底统一了 Tools 的暴露与调用方式。
二、MCP 的两种通信方式
MCP 官方提供了两种主流传输方式:
三、STDIO 方式详解
1. MCP Server(服务端)
① 使用现成的公共 MCP Server
网上已有大量现成的 MCP 服务,例如:
- MCP Server 聚合站 提供了百度地图、文件系统、天气查询等众多 MCP Server。
② 自定义 STDIO MCP Server
下面我们用 Spring AI 创建一个自定义的 STDIO MCP Server。
第一步:添加依赖(pom.xml)
<!--MCP Server 依赖--><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server</artifactId></dependency><!--Spring AI BOM 管理--><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><!--打包插件(用于生成可执行 jar)--><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>第二步:编写 Tool 服务
@ServicepublicclassUserToolService{Map<String,Double>userScore=Map.of("xushu",99.0,"zhangsan",2.0,"lisi",3.0);@Tool(description="获取用户分数")publicStringgetScore(Stringusername){if(userScore.containsKey(username)){returnuserScore.get(username).toString();}return"未检索到当前用户 "+username;}}第三步:暴露 Tool
@BeanpublicToolCallbackProviderweatherTools(UserToolServiceuserToolService){returnMethodToolCallbackProvider.builder().toolObjects(userToolService).build();}第四步:配置文件(application.yml)
spring:main:banner-mode:off# 必须关闭横幅,否则影响 STDIO 通信ai:mcp:server:name:my-weather-serverversion:0.0.1⚠️ 注意:必须禁用横幅和控制台日志,否则会污染标准输入输出流,导致 MCP 通信失败。
第五步:打包
执行 mvn package,在 target/ 下生成可执行 jar 包。
2. MCP Client(客户端)调用 STDIO
第一步:依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency>第二步:配置 application.yml
spring:ai:mcp:client:request-timeout:60000stdio:servers-configuration:classpath:/mcp-servers-config.jsonconnections:server1:command:/path/to/serverargs:---port=8080---mode=productionenv:API_KEY:your-api-keyDEBUG:"true"第三步:mcp-servers-config.json(放在 resources 下)
{"mcpServers":{"baidu-map":{"command":"cmd","args":["/c","npx","-y","@baidumap/mcp-server-baidu-map"],"env":{"BAIDU_MAP_API_KEY":"你的百度地图Key"}},"mcp-server-weather":{"command":"java","args":["-Dspring.ai.mcp.server.stdio=true","-Dlogging.pattern.console=","-jar","D:\\xxx\\target\\mcp-stdio-server.jar"]}}}第四步:绑定到 ChatClient
@RestControllerpublicclassOpenAiController{privatefinalChatClientchatClient;publicOpenAiController(DashScopeChatModeldashScopeChatModel,ToolCallbackProvidermcpTools){this.chatClient=ChatClient.builder(dashScopeChatModel).defaultToolCallbacks(mcpTools).build();}@GetMapping(value="/ai/generateStream",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>generateStream(@RequestParamStringmessage){returnchatClient.prompt().user(message).stream().content();}}3. STDIO 方式鉴权
STDIO 通过环境变量传递凭证。
在客户端配置中,通过 env 字段注入:
{"mcpServers":{"baidu-map":{"command":"cmd","args":["/c","npx","-y","@baidumap/mcp-server-baidu-map"],"env":{"BAIDU_MAP_API_KEY":"your-valid-key"}}}}服务端获取环境变量进行校验:
@Tool(description="获取用户余额")publicStringgetScore(){StringapiKey=System.getenv("BAIDU_MAP_API_KEY");// 校验 apiKey 合法性...return"用户信息";}⚠️ 局限:STDIO 环境下,环境变量在子进程启动时固定,不支持动态切换用户凭证。多用户场景下会产生争抢,只适合单租户或本地工具。
四、SSE 方式详解
1. MCP Server(服务端)
第一步:依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webmvc</artifactId></dependency>注意:如果用 webflux 版本,可能需要设置 spring.main.web-application-type=reactive,建议根据官方说明选择。
第二步:定义 Tool(同 STDIO)
@ServicepublicclassUserToolService{Map<String,Double>userScore=Map.of("xushu",99.0,"zhangsan",2.0,"lisi",3.0);@Tool(description="获取用户分数")publicStringgetScore(Stringusername){if(userScore.containsKey(username)){returnuserScore.get(username).toString();}return"未检索到当前用户 "+username;}}第三步:暴露 Tool
@BeanpublicToolCallbackProvidertoolProvider(UserToolServiceuserToolService){returnMethodToolCallbackProvider.builder().toolObjects(userToolService).build();}第四步:配置文件 application.yml
server:port:8088启动后,MCP Server 会暴露 SSE 端点(通常是 /sse)。
2. MCP Client(客户端)
第一步:依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency>第二步:配置
spring:ai:mcp:client:enabled:truename:my-mcp-clientversion:1.0.0request-timeout:30stype:ASYNCsse:connections:server1:url:http://localhost:8088第三步:代码绑定将 ToolCallbackProvider 注入 ChatClient 即可
@RestControllerpublicclassOpenAiController{privatefinalChatClientchatClient;publicOpenAiController(DashScopeChatModeldashScopeChatModel,ToolCallbackProvidermcpTools){this.chatClient=ChatClient.builder(dashScopeChatModel).defaultToolCallbacks(mcpTools).build();}@GetMapping(value="/ai/generateStream",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>generateStream(@RequestParamStringmessage){returnchatClient.prompt().user(message).stream().content();}}3. SSE 方式鉴权(OAuth2)
SSE 基于 HTTP,天然适合使用 OAuth2 标准。
MCP 规范(2025 年 3 月版)明确支持 OAuth2,MCP Server 同时充当 资源服务器 和 授权服务器。
- 资源服务器:校验每个请求的 Authorization: Bearer 头。
- 授权服务器:颁发 access_token(通常使用 client_credentials 模式)。