前言
预训练的大语言模型虽然强大,但是知识库停留在训练的那一刻,无法获取实时的数据,导致大模型在某些场景下表现的很不好。
例如,你询问大模型关于实时天气、实时新闻的看法,大模型要么无法回答,要么胡乱编造结果,这显然不是我们想看到的结果。
好在,MCP 协议的诞生,打通了 AI 应用和外部系统的集成问题,大模型不仅可以获取互联网上公开的最新数据,甚至可以访问企业内部系统的保密数据,只要你开发好相应的MCP服务器即可。
本文通过一个“天气MCP服务器”为例。
MCP服务器开发
MCP 是 Model Context Protocol 的缩写,中文译为“模型上下文协议”。
协议即标准,有了标准,厂商就可以根据标准开发并封装成依赖包,减少重复开发的成本。官方提供了各语言的开发包,以 Java 为例,仓库地址:github.com/modelcontex…
在 Spring 项目中,为了更好的集成 MCP,Spring 做了进一步的封装。
首先,引入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>
如果通过webmvc
的方式集成,就引入spring-ai-starter-mcp-server-webmvc
<dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> </dependency></dependencies>
到这里,环境就搭建好了。
MCP 服务器,最核心的是 Tool 的开发。Tool 是供 MCP 客户端调用的工具,由大模型负责推理该调用哪个 Tool。在代码层面,Tool 就是一个普通的 Java 方法,额外要做的,就是对这个方法加以描述,让大模型能理解,这个方法是干什么用的,需要哪些参数。
如下所示,方法weatherQuery
就是一个 Tool,通过@Tool
注解对方法加以描述,让 Spring 知道有这么个 Tool。为了简单,这里数据是随机生成的。
@Servicepublic class WeatherService { @Tool(name = "weather_query", description = "根据商品关键字搜索商品,返回一个商品列表") public String weatherQuery(@ToolParam(description = "位置", required = true) String location) { // 天气、温度 随机生成 int temperature = ThreadLocalRandom.current().nextInt(10, 40); String[] weathers = {"晴", "多云", "阴", "小雨", "中雨", "大雨", "雨夹雪", "大雪"}; String weatherText = weathers[ThreadLocalRandom.current().nextInt(weathers.length)]; return "location=%s,temperature=%d°C,weatherText=%s".formatted(location, temperature, weatherText); }}
最后,将包含 Tool 的对象封装到 ToolCallbackProvider,注册到 Spring 上下文容器,再由 Spring 注册到 MCP 服务器。
@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public ToolCallbackProvider toolCallbackProvider(WeatherService weatherService) { return MethodToolCallbackProvider.builder().toolObjects(weatherService).build(); }}
启动 Spring 应用,访问http://127.0.0.1:8080/sse
能打开新的会话,表示MCP服务正常。
MCP 服务器默认由两个端点:
- /sse sse连接,创建会话的端点**/mcp/message **MCP客户端和服务器消息收发的端点
如果像修改端点,可以通过如下配置:
spring: ai: mcp: server: enabled: true type: sync sse-endpoint: /sse sse-message-endpoint: /mcp/message
MCP客户端测试
MCP 服务器开发好以后,可以对外发布,然后添加到大模型服务平台,供AI应用调用。
当然,我们也可以先通过 MCP 客户端本地调试下,确保没问题,再发布。
开发 MCP 客户端,需要先引入依赖
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency>
然后,构建 McpSyncClient 和服务器建立连接,并通信。
如下所示,先初始化,再列举服务器支持的 Tools。
public static void main(String[] args) { McpClientTransport transport = new HttpClientSseClientTransport("http://127.0.0.1:8080/sse"); McpSyncClient client = McpClient.sync(transport) .requestTimeout(Duration.ofSeconds(10)) .capabilities(McpSchema.ClientCapabilities.builder().roots(false).build()) .build(); // 初始化 McpSchema.InitializeResult initialize = client.initialize(); // 列举服务器支持的Tools McpSchema.ListToolsResult tools = client.listTools(); for (McpSchema.Tool tool : tools.tools()) { System.err.println(tool); } client.closeGracefully();}
正常情况下应该有下图所示的输出
客户端发起 Tool 调用,代码示例:
McpSchema.CallToolRequest callToolRequest = new McpSchema.CallToolRequest("weather_query", Map.of("location", "杭州"));McpSchema.CallToolResult callToolResult = client.callTool(callToolRequest);System.err.println(callToolResult.content());
正常应该得到结果
[TextContent[audience=null, priority=null, text="location=杭州,temperature=38°C,weatherText=中雨"]]
部署到大模型服务平台
自己写 MCP 客户端去调用 MCP 服务器是没有意义的,MCP 服务器对外部署后,可以注册到大模型服务平台,供所有AI应用调用,增强AI应用的能力。
这里以阿里云的百炼为例,官网地址:bailian.console.aliyun.com
注册账号后,在“MCP管理”页面创建MCP服务,如下图所示:
依次填写MCP服务的名称、描述、和服务配置。因为MCP服务器我们已经开发部署完了,所以这里选http的安装方式,填写MCP服务器地址即可。
平台会创建MCP客户端和MCP服务器通信,列举服务器支持的所有工具。
可以在页面上,直接对工具发起调用,进行调试。
MCP 服务调试完成,就可以直接添加到智能体,在用户和大模型对话时,大模型会智能判断何时调用哪个工具。
例如,我们问天气相关的问题,大模型就会判断该调用天气工具了,然后MCP客户端就会发起工具调用,然后再把天气结果喂给大模型,由大模型推理回答。