一、在 AI 应用开发中,模型常常面临以下限制:

  • 时效性问题:模型只能基于训练时的数据,无法获取实时信息
  • 能力边界:模型无法执行外部操作,如访问数据库、调用 API
  • 数据访问限制:模型无法直接获取私有或本地数据

MCP 正是为了解决这些问题而设计,它为 AI 模型提供了一个标准化的桥梁,使其能够与外部工具、资源和数据源进行交互,从而突破模型能力的边界。

很多人觉得 Model Context Protocol (MCP) 很神秘、很复杂,但其实它非常简单。MCP 就像是 AI 模型的"工具箱",让 AI 不再局限于训练数据,而是可以实时调用外部工具和服务。

简单来说,MCP 就是 AI 模型的"增强版 HTTP 协议":

  • HTTP 协议让浏览器能够访问网页和服务器资源
  • MCP 协议让 AI 模型能够访问外部工具、资源和数据

1.2 MCP 解决的核心问题

以下是 HTTP 协议与 MCP 协议在协议层面的对比:

协议层面 HTTP 协议 Model Context Protocol (MCP)
协议基础 基于 TCP/IP,使用文本格式 基于 JSON-RPC 2.0,使用 JSON 格式
请求-响应模式 请求-响应,无状态 请求-响应,支持会话状态
方法类型 GET、POST、PUT、DELETE、PATCH 等 tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get 等
消息结构 请求行、请求头、请求体 JSON 对象,包含 id、method、params、jsonrpc 字段
错误处理 HTTP 状态码 (200, 404, 500 等) JSON-RPC 错误对象,包含 code、message 字段
认证方式 Authorization 头、Cookie、OAuth 等 标准化认证机制,支持令牌传递
数据格式 支持多种 MIME 类型 统一使用 JSON 格式
扩展性 通过自定义 Header 扩展 通过定义新的方法和参数结构扩展
传输层 主要基于 TCP,通过 TLS 实现安全传输 可通过 STDIO、HTTP/SSE、WebSocket 等多种方式传输
连接管理 连接复用、持久连接 长连接,支持双向通信
上下文管理 无内置上下文管理 内置上下文管理,支持工具、资源、提示的标准化交互

Client/Server 层:McpCient 处理客户端操作,McpServer 管理服务端协议操作,二者均通过 McpSession 进行通信管理。

Session 层(McpSession):通过 DefaultMcpSession 实现管理通信模式及状态。

Transport 层(McpTransport):处理 JSON-RPC 消息的序列化与反序列化,支持多种传输协议实现。

二、 开发 MCP 服务器

MCP 提供了创建 MCP 服务器的能力,使我们能够将自定义功能暴露给 AI 模型。在 Spring AI 生态系统中,MCP 服务器的开发变得更为简单和标准化。

1.1 Spring AI MCP 服务器基础概念

Spring AI 提供了 MCP 服务器启动器,允许开发者通过简单的注解将 Spring Boot 应用转换为 MCP 服务器。MCP 服务器本质上是一个能够通过标准化协议与 AI 模型通信的服务,支持以下核心功能:

  • 工具暴露:通过注解将 Spring 方法暴露为可调用的工具
  • 资源管理:提供对系统资源的标准化访问
  • 提示管理:提供参数化提示的生成和管理
  • 传输协议:支持 STDIO 和 HTTP/SSE 传输协议

1.3 创建第一个 MCP 工具

在 Spring AI 中,创建 MCP 工具非常简单,只需要使用 @McpTool 注解:

import org.springframework.ai.mcp.server.annotation.McpTool;import org.springframework.stereotype.Component;@Componentpublic class SimpleMcpServer {        @McpTool(description = "A simple greeting tool")    public String greet(String name) {        return "Hello, " + name + "!";    }}

1.4 工具参数定义

Spring AI 支持通过参数注解定义工具参数的详细信息:

import org.springframework.ai.mcp.server.annotation.McpTool;import org.springframework.ai.mcp.server.annotation.McpToolParameter;import org.springframework.stereotype.Component;@Componentpublicclass WeatherMcpServer {    @McpTool(description = "Get current weather information for a city")    public String getWeather(            @McpToolParameter(description = "The city name to get weather for") String city,            @McpToolParameter(description = "The country code (optional)") String country) {                // 实际应用中,这里会调用真实的天气 API        // 为演示目的,返回模拟数据        return String.format("The current weather in %s, %s is sunny with a temperature of 22°C.",                            city, country != null ? country : "Country not specified");    }}

1.5 结构化内容返回

Spring AI 支持返回复杂对象作为结构化内容:

public record WeatherData(String location, int temperature, String condition) {}@Componentpublic class WeatherMcpServer {        @McpTool(description = "Get detailed weather information", returnsStructuredContent = true)    public WeatherData getDetailedWeather(@McpToolParameter String city) {        return new WeatherData(city, 22, "Sunny");    }}

1.6 资源定义

除了工具,Spring AI 还支持定义 MCP 资源:

import org.springframework.ai.mcp.server.annotation.McpResource;import org.springframework.ai.mcp.server.annotation.McpResourceParameter;import org.springframework.stereotype.Component;@Componentpublic class ResourceMcpServer {        @McpResource(description = "Get content of a file")    public String getFileContent(@McpResourceParameter String filePath) {        // 读取文件内容        return "File content...";    }}

1.7 提示定义

Spring AI 支持定义可参数化的 MCP 提示:

import org.springframework.ai.mcp.server.annotation.McpPrompt;import org.springframework.ai.mcp.server.annotation.McpPromptParameter;import org.springframework.stereotype.Component;@Componentpublic class PromptMcpServer {        @McpPrompt(description = "Generate a personalized greeting message")    public String greetingPrompt(            @McpPromptParameter(description = "The name of the person to greet") String name,            @McpPromptParameter(description = "The tone of the greeting") String tone) {        return String.format("Please generate a %s greeting for %s", tone, name);    }}

1.8 配置 MCP 服务器

Spring AI MCP 服务器可以通过配置文件进行配置:

spring:  ai:    mcp:      server:        enabled:true        transport:          stdio:            enabled:true          http:            enabled:true            port:8080        tools:          auto-registration:true

1.10 Spring AI MCP 服务器架构图

Spring AI MCP 服务器的架构如下:

1.1 MCP 服务器开发时序图

1.11 MCP 服务器开发流程

  1. 添加依赖:在项目中添加 Spring AI MCP 服务器启动器
  2. 创建工具:使用 @McpTool 注解创建可调用的工具
  3. 配置服务器:通过配置文件或注解配置服务器行为
  4. 启动服务器:作为标准 Spring Boot 应用启动

1.12 MCP 服务器关键特性

1.11.1 工具定义
  • 使用 @McpTool 注解定义工具,包含描述信息
  • 使用 @McpToolParameter 注解定义工具参数,包含参数描述
  • 支持返回字符串结果或结构化内容
1.11.2 依赖管理
  • 通过 Spring Boot 启动器简化依赖管理
  • 与 Spring 生态系统无缝集成
1.11.3 高级功能支持
  • 自动注册:工具可以自动注册到 MCP 服务器
  • 参数验证:支持参数类型和格式验证
  • 错误处理:集成 Spring 的错误处理机制

从第一性原理思考 MCP 服务器的开发,我们需要解决以下基本问题:

  • 工具暴露:如何将 Spring 方法暴露为 MCP 工具?通过注解和 Spring 的 AOP 机制
  • 参数映射:如何将 JSON 参数映射到 Java 方法参数?通过 Spring 的数据绑定机制
  • 结果序列化:如何将 Java 返回值转换为 MCP 格式?通过 Spring 的 JSON 序列化
  • 错误处理:如何处理和传播错误?通过 Spring 的异常处理机制
  • 生命周期管理:如何管理服务器生命周期?通过 Spring 容器管理

三、 MCP 客户端架构概览

MCP 客户端是连接 AI 应用和 MCP 服务器的桥梁。以下是客户端的整体架构:

2.1 整体架构流程图

2.2 核心组件交互流程

四、 MCP 客户端核心组件详解

3.1 McpClient 接口

McpClient 是 MCP 实现的核心接口,定义了与 MCP 服务器交互的所有功能:

public interface McpClient extends AutoCloseable {    String key();    List<ToolSpecification> listTools();    ToolExecutionResult executeTool(ToolExecutionRequest executionRequest);    List<McpResource> listResources();    List<McpResourceTemplate> listResourceTemplates();    McpReadResourceResult readResource(String uri);    List<McpPrompt> listPrompts();    McpGetPromptResult getPrompt(String name, Map<String, Object> arguments);    void checkHealth();    void setRoots(List<McpRoot> roots);}

3.2 DefaultMcpClient 实现

DefaultMcpClientMcpClient 的主要实现,具备以下关键特性:

从第一性原理思考,DefaultMcpClient 的设计解决了以下基本问题:

  • 网络开销优化:每次调用都查询工具列表会带来网络开销,因此需要缓存机制
  • 并发管理:在异步环境中需要管理并发操作,因此使用 ID 机制关联请求和响应
  • 连接管理:网络连接可能不稳定,需要健康检查和自动重连机制
  • 状态管理:需要维护客户端的各种状态,如工具列表、资源引用等
工具列表缓存机制
@Overridepublic List<ToolSpecification> listTools() {    if (isToolListRefreshNeeded()) {        CompletableFuture<Void> updateInProgress = this.toolListUpdateInProgress.get();        if (updateInProgress != null) {            // 如果更新正在进行,等待完成            updateInProgress.join();            return toolListRefs.get();        } else {            // 否则开始新的更新            CompletableFuture<Void> update = new CompletableFuture<>();            this.toolListUpdateInProgress.set(update);            try {                obtainToolList();            } finally {                update.complete(null);                toolListOutOfDate.set(false);                toolListUpdateInProgress.set(null);            }            return toolListRefs.get();        }    } else {        return toolListRefs.get();    }}
健康检查和自动重连
private void startAutoHealthCheck() {    if (Boolean.FALSE.equals(autoHealthCheck)) {        return;    }    Runnable healthCheckTask = () -> {        try {            checkHealth();        } catch (Exception e) {            log.warn("mcp server health check failed. Attempting to reconnect...", e);            triggerReconnection();        }    };    healthCheckScheduler.scheduleAtFixedRate(        healthCheckTask,        autoHealthCheckInterval.toMillis(),        autoHealthCheckInterval.toMillis(),        TimeUnit.MILLISECONDS);}

3.3 McpToolProvider 工具提供者

McpToolProvider 将 MCP 服务器提供的工具转换为 LangChain4j 可用的工具:

从第一性原理思考,工具提供者的设计解决了以下基本问题:

  • 系统集成:如何将 MCP 工具集成到 LangChain4j 的工具系统?通过适配器模式
  • 多客户端管理:如何管理多个 MCP 客户端?通过组合模式
  • 工具过滤:如何支持工具的过滤和选择?通过策略模式
  • 工具包装:如何支持工具的功能增强?通过装饰器模式
public class McpToolProvider implements ToolProvider {    privatefinal CopyOnWriteArrayList<McpClient> mcpClients;        @Override    public ToolProviderResult provideTools(ToolProviderRequest request) {        ToolProviderResult.Builder builder = ToolProviderResult.builder();        for (McpClient mcpClient : mcpClients) {            var defaultToolExecutor = new McpToolExecutor(mcpClient);            try {                mcpClient.listTools().stream()                        .filter(tool -> mcpToolsFilter.get().test(mcpClient, tool))                        .forEach(toolSpecification -> {                            builder.add(toolSpecification, toolWrapper.apply(defaultToolExecutor));                        });            } catch (Exception e) {                if (failIfOneServerFails) {                    thrownew RuntimeException("Failed to retrieve tools from MCP server", e);                } else {                    log.warn("Failed to retrieve tools from MCP server", e);                }            }        }        return builder.build();    }}

五、 MCP 客户端传输协议实现

4.1 STDIO 传输协议

STDIO 传输通过标准输入输出与本地进程通信:

从第一性原理思考,传输协议的设计需要考虑不同部署场景的基本需求:

  • 本地执行场景:需要高效、低延迟的通信,因此选择 STDIO
  • 网络部署场景:需要跨网络的通信能力,因此选择 HTTP/SSE
  • 容器化部署场景:需要容器隔离和管理,因此选择 Docker
public class StdioMcpTransport implements McpTransport {    privatefinal List<String> command;    privatefinal Map<String, String> environment;    private Process process;    private ProcessIOHandler processIOHandler;        @Override    public void start(McpOperationHandler messageHandler) {        this.messageHandler = messageHandler;        ProcessBuilder processBuilder = new ProcessBuilder(command);        processBuilder.environment().putAll(environment);        try {            process = processBuilder.start();        } catch (Exception e) {            thrownew RuntimeException(e);        }        processIOHandler = new ProcessIOHandler(process, messageHandler, logEvents);        new Thread(processIOHandler).start();    }}

4.2 HTTP/SSE 传输协议

HTTP/SSE 传输使用 Server-Sent Events 接收消息,HTTP POST 发送请求:

public class HttpMcpTransport implements McpTransport {    privatefinal String sseUrl;    privatefinal Map<String, String> customHeaders;    privatefinal OkHttpClient client;    private EventSource mcpSseEventListener;        private EventSource startSseChannel(boolean logResponses) {        Request request = new Request.Builder()            .url(sseUrl)            .headers(buildCommonHeaders())            .build();        CompletableFuture<String> initializationFinished = new CompletableFuture<>();        SseEventListener listener = new SseEventListener(            messageHandler, logResponses, initializationFinished, onFailure);        EventSource eventSource = EventSources.createFactory(client).newEventSource(request, listener);                // 等待初始化完成,获取 POST URL        try {            int timeout = client.callTimeoutMillis() > 0 ? client.callTimeoutMillis() : Integer.MAX_VALUE;            String relativePostUrl = initializationFinished.get(timeout, TimeUnit.MILLISECONDS);            postUrl = buildAbsolutePostUrl(relativePostUrl);        } catch (Exception e) {            thrownew RuntimeException(e);        }        return eventSource;    }}

五、 协议消息处理

5.1 消息结构

MCP 协议基于 JSON-RPC 2.0:

从第一性原理思考,协议设计需要解决以下基本问题:

  • 请求-响应匹配:在异步通信中,如何匹配请求和响应?解决方案是使用唯一的消息 ID
  • 错误处理:如何统一处理各种错误情况?通过标准的错误消息格式
  • 通知机制:如何支持服务器向客户端发送通知?通过无 ID 的通知消息
  • 标准化:为什么选择 JSON-RPC 2.0?因为它是一个成熟、轻量级、广泛支持的标准协议
public class McpClientMessage {    public final String jsonrpc = "2.0";    private Long id;        public McpClientMessage(Long id) {        this.id = id;    }}

5.2 消息类型

public enum McpClientMethod {    @JsonProperty("initialize") INITIALIZE,    @JsonProperty("tools/call") TOOLS_CALL,    @JsonProperty("tools/list") TOOLS_LIST,    @JsonProperty("resources/list") RESOURCES_LIST,    @JsonProperty("resources/read") RESOURCES_READ,    @JsonProperty("prompts/list") PROMPTS_LIST,    @JsonProperty("prompts/get") PROMPTS_GET,    @JsonProperty("ping") PING,    @JsonProperty("notifications/roots/list_changed") NOTIFICATION_ROOTS_LIST_CHANGED}

5.3 消息分发处理

McpOperationHandler 负责处理来自服务器的消息:

public class McpOperationHandler {    privatefinal Map<Long, CompletableFuture<JsonNode>> pendingOperations;        public void handle(JsonNode message) {        if (message.has("id")) {            // 处理响应消息            long messageId = message.get("id").asLong();            if (message.has("result") || message.has("error")) {                // 完成等待中的操作                CompletableFuture<JsonNode> op = pendingOperations.remove(messageId);                if (op != null) {                    op.complete(message);                }            } else {                // 处理服务器发起的操作                handleServerInitiatedOperation(message);            }        } elseif (message.has("method")) {            // 处理通知消息            handleNotification(message);        }    }}

六、 工具执行流程

6.1 工具发现流程

@Overridepublic List<ToolSpecification> listTools() {    if (isToolListRefreshNeeded()) {        obtainToolList();    }    return toolListRefs.get();}private synchronized void obtainToolList() {    McpListToolsRequest operation = new McpListToolsRequest(idGenerator.getAndIncrement());    CompletableFuture<JsonNode> resultFuture = transport.executeOperationWithResponse(operation);    JsonNode result = null;    try {        result = resultFuture.get();    } catch (InterruptedException | ExecutionException e) {        thrownew RuntimeException(e);    } finally {        pendingOperations.remove(operation.getId());    }        final List<ToolSpecification> toolList = ToolSpecificationHelper.toolSpecificationListFromMcpResponse(        (ArrayNode) result.get("result").get("tools"));    toolListRefs.set(toolList);}

6.2 工具执行流程

@Overridepublic ToolExecutionResult executeTool(ToolExecutionRequest executionRequest) {    ObjectNode arguments = null;    try {        String args = executionRequest.arguments();        if (isNullOrBlank(args)) {            args = "{}";        }        arguments = OBJECT_MAPPER.readValue(args, ObjectNode.class);    } catch (JsonProcessingException e) {        thrownew ToolArgumentsException(e);    }        long operationId = idGenerator.getAndIncrement();    McpCallToolRequest operation = new McpCallToolRequest(operationId, executionRequest.name(), arguments);        CompletableFuture<JsonNode> resultFuture = transport.executeOperationWithResponse(operation);    JsonNode result = resultFuture.get(timeoutMillis, TimeUnit.MILLISECONDS);        return ToolExecutionHelper.extractResult(result);}

七、MCP 客户端实际应用示例

7.1 HTTP 传输配置

// 配置 HTTP 传输McpTransport transport = new HttpMcpTransport.Builder()    .sseUrl("http://localhost:8080/mcp/sse")    .logRequests(true)    .logResponses(true)    .build();// 创建 MCP 客户端McpClient mcpClient = new DefaultMcpClient.Builder()    .transport(transport)    .toolExecutionTimeout(Duration.ofSeconds(60))    .build();

7.2 STDIO 传输配置

// 配置 STDIO 传输McpTransport transport = new StdioMcpTransport.Builder()    .command(List.of(        "java", "-jar", "mcp-server.jar",        "--port", "8080"    ))    .logEvents(true)    .build();// 创建 MCP 客户端McpClient mcpClient = new DefaultMcpClient.Builder()    .transport(transport)    .build();

7.3 工具集成示例

// 创建工具提供者McpToolProvider toolProvider = McpToolProvider.builder()    .mcpClients(mcpClient)    .filterToolNames("weather", "calculator")    .build();// 在 AI 服务中使用ChatLanguageModel model = OpenAiChatModel.builder()    .apiKey(System.getenv("OPENAI_API_KEY"))    .build();MyAiService aiService = AiServices.builder(MyAiService.class)    .chatLanguageModel(model)    .chatMemory(MessageWindowChatMemory.withMaxMessages(10))    .toolProvider(toolProvider)    .build();

八、 高级特性

8.1 资源转工具

McpResourcesAsToolsPresenter resourcesAsToolsPresenter =     new DefaultMcpResourcesAsToolsPresenter();McpToolProvider toolProvider = McpToolProvider.builder()    .mcpClients(mcpClient)    .resourcesAsToolsPresenter(resourcesAsToolsPresenter)    .build();

8.2 自动健康检查

McpClient mcpClient = new DefaultMcpClient.Builder()    .transport(transport)    .autoHealthCheck(true)    .autoHealthCheckInterval(Duration.ofSeconds(30))    .reconnectInterval(Duration.ofSeconds(5))    .build();

九、 总结

通过 MCP,AI 应用能够轻松集成各种外部服务,大大扩展了模型的能力边界,为构建更强大的 AI 系统提供了坚实的基础。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐