一、简介
MCP 就像 AI 领域的 JDBC:以前大模型要用外部工具时,每个项目都要自己定义调用方式,重复又混乱;MCP 统一了协议,模型能像调用标准接口一样去用数据库、API 或服务,开发者少写胶水代码,工具也能跨项目复用。
https://modelcontextprotocol.io/docs/getting-started/intro
https://docs.langchain4j.dev/tutorials/mcp/
二、调用上万个通用的MCP
https://mcp.so/zh
阿里云百炼也有类似的,但是数量较少
三、MCP架构知识
MCP遵循客户端-服务器架构包含以下几个核心部分
- MCP 主机(MCP Hosts):发起请求的 AI 应用程序,比如聊天机器人、AI 驱动的 IDE 等。
- MCP 客户端(MCP Clients):在主机程序内部,与 MCP 服务器保持 1:1 的连接。
- MCP 服务器(MCP Servers):为 MCP 客户端提供上下文、工具和提示信息。
- 本地资源(Local Resources):本地计算机中可供 MCP 服务器安全访问的资源,如文件、数据库。
- 远程资源(Remote Resources):MCP 服务器可以连接到的远程资源,如通过 API 提供的数据
在MCP通信协议中,一般有两种模式
STDIO(标准输入/输出)
支持标准输入和输出流进行通信,主要用于本地集成、命令行工具等场景
SSE (Server-Sent Events)
支持使用 HTTP POST,请求进行服务器到客户端流式处理,以实现客户端到服务器的通信
两者对比
四、代码实战
前置环境
首先下载nodejs环境
注册百度地图账号+申请API-key
https://lbsyun.baidu.com/apiconsole/key
nodejs配置编码
开发步骤
建module
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.liming</groupId>
<artifactId>langchain4j-v1</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>langchain4j-14chat-mcp</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai 基础-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!--langchain4j 高阶-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<!-- langchain4j-reactor实现流式输出 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency>
<!--DashScope (Qwen)接入阿里云百炼平台
https://docs.langchain4j.dev/integrations/language-models/dashscope
-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>
<!-- MCP Client 依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml
server:
port: 9014
servlet:
encoding:
charset: UTF-8
enabled: true
force: true
spring:
application:
name: langchain4j-14chat-mcp
langchain4j:
community:
dashscope:
streaming-chat-model:
api-key: ${aliQwen-api}
model-name: qwen-plus
chat-model:
api-key: ${aliQwen-api}
model-name: qwen-plus
主启动
package com.liming;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class McpLangChain4JApp {
public static void main(String[] args) {
SpringApplication.run(McpLangChain4JApp.class, args);
}
}
业务类
新建接口McpService
package com.liming.service;
import reactor.core.publisher.Flux;
public interface McpService {
Flux<String> chat(String question);
}
controller
package com.liming.controller;
import com.liming.service.McpService;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.tool.ToolProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
import java.util.Map;
/**
* @Description: 知识出处
* <p>
* 第1步,如何进行mcp编码
* https://docs.langchain4j.dev/tutorials/mcp#creating-an-mcp-tool-provider
* <p>
* 第2步,如何使用baidu map mcp,它提供了哪些功能对外服务
* https://mcp.so/zh/server/baidu-map/baidu-maps?tab=tools
* <p>
* http://localhost:9014/mcp/chat?question=查询61.149.121.66归属地
* http://localhost:9014/mcp/chat?question=查询北京天气
* http://localhost:9014/mcp/chat?question=查询昌平到天安门路线规划
*/
@RestController
public class McpCallServerController {
@Autowired
private StreamingChatModel streamingChatModel;
@GetMapping("/mcp/chat")
public Flux<String> chat(@RequestParam("question") String question) {
/**1.构建McpTransport协议
*
* 1.1 cmd:启动 Windows 命令行解释器。
* 1.2 /c:告诉 cmd 执行完后面的命令后关闭自身。
* 1.3 npx:npx = npm execute package,Node.js 的一个工具,用于执行 npm 包中的可执行文件。
* 1.4 -y 或 --yes:自动确认操作(类似于默认接受所有提示)。
* 1.5 @baidumap/mcp-server-baidu-map:要通过 npx 执行的 npm 包名
* 1.6 BAIDU_MAP_API_KEY 是访问百度地图开放平台API的AK
*/
McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("cmd", "/c", "npx", "-y", "@baidumap/mcp-server-baidu-map"))
.environment(Map.of("BAIDU_MAP_API_KEY", System.getenv("BAIDU_MAP_API_KEY")))
.build();
// 2.构建McpClient客户端
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.build();
// 3.创建工具集和原生的FunctionCalling类似
ToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(mcpClient)
.build();
// 4.通过AiServivces给我们自定义接口McpService构建实现类并将工具集和大模型赋值给AiService
McpService mcpService = AiServices.builder(McpService.class)
.streamingChatModel(streamingChatModel)
.toolProvider(toolProvider)
.build();
// 5.调用我们定义的HighApi接口,通过大模型对百度mcpserver调用
return mcpService.chat(question);
}
}
五、复习
- Function Calling,为了让大模型使用Util工具
- RAG,为了让大模型获取足够的上下文
- MCP,为了让大模型之间的调用