从零搭建工业级Java Agent:Claude Code架构拆解12节完整教程
引言:随着AI Agent技术的爆发,越来越多开发者想从0到1掌握Agent的设计与落地,但市面上大多教程停留在“概念讲解”,缺乏与真实项目结合的实操指导。本文基于Claude Code(Java版)项目,拆解12节渐进式课程,从Agent基础概念到工业级工程化落地,每一节都对应真实项目代码,看完就能上手搭建自己的AI Agent,适合Java开发者、AI工程爱好者学习。
第09课:MCP协议(Model Context Protocol)全解析——官方标准工具扩展协议实现
一、前言
上一节课我们完成了Agent异常处理与容错机制的设计,通过“分层捕获+责任链处理+智能重试+断点续跑”的体系,解决了工具调用失败、LLM响应异常、系统宕机等核心问题,确保了Agent运行的稳定性和任务连续性。在此基础上,工业级Java Agent要实现工具扩展、跨服务协同,核心依赖MCP协议——即Model Context Protocol(模型上下文协议),它是官方标准的Agent工具扩展协议,负责规范Agent与工具、Agent与远程服务之间的通信规则,是Agent实现工具动态扩展、本地/远程服务对接的核心基础,也是本节课的唯一核心内容。
很多开发者在搭建Agent时,容易混淆MCP协议的定位,误将其作为普通通信协议使用,忽略其“工具扩展标准化”的核心价值,导致工具对接混乱、远程服务无法兼容。本节课我们将聚焦MCP协议本身,从协议定义、核心特性、StdIO通信方式、工具动态发现、本地/远程服务对接,到.mcp.json配置文件加载逻辑,结合核心源码逐一拆解,教你从零实现符合官方标准的MCP协议,让Agent具备标准化工具扩展和跨服务通信能力。
核心结论:MCP(Model Context Protocol)协议是Agent工具扩展的官方标准协议,核心解决“工具标准化对接、资源动态发现、本地/远程服务统一通信”三大问题,其StdIO通信方式保证轻量性,.mcp.json配置保证灵活性,是工业级Agent实现工具扩展的核心支撑。
二、MCP协议核心定义与核心特性
1. 协议定义
MCP(Model Context Protocol)——模型上下文协议,是AI Agent领域官方标准化的工具扩展协议,定义了Agent与工具(本地工具、远程工具)、Agent与MCP服务之间的通信格式、交互流程和配置规范,核心目标是实现“工具即插即用、服务无缝对接”,让不同开发者开发的工具、不同部署方式的服务,都能按照统一标准与Agent协同工作。
与普通通信协议(如HTTP、TCP)不同,MCP协议专门针对Agent场景设计,内置模型上下文传递、工具元信息交互、请求容错等特性,无需额外封装即可适配Agent与工具的交互需求,是Agent工具扩展的“通用接口”。
2. 核心特性(官方标准规范)
(1)标准化工具扩展:定义统一的工具注册、调用、响应格式,任何工具只要遵循MCP协议规范,即可无缝接入Agent,无需修改Agent核心代码;
(2)轻量StdIO通信:默认采用StdIO(标准输入输出)作为核心通信方式,无需额外依赖网络组件,轻量高效,同时支持兼容TCP/UDP通信,适配不同部署场景;
(3)动态发现工具与资源:支持Agent启动时自动扫描本地工具、远程MCP服务中的工具资源,自动注册工具元信息,实现工具“即插即用”;
(4)本地/远程双模式对接:支持本地MCP服务(单机部署)和远程MCP服务(集群部署)无缝对接,Agent可根据配置自动切换对接模式,适配不同部署需求;
(5)配置驱动:通过.mcp.json配置文件统一管理MCP协议参数、工具信息、服务地址等,支持动态加载配置,无需重启Agent即可更新配置。
三、MCP协议核心实现(源码解析+官方规范)
本节课围绕MCP协议核心要点,结合Claude Code真实源码,逐一实现官方标准的MCP协议功能,重点覆盖StdIO通信、工具动态发现、本地/远程对接、.mcp.json配置加载,所有代码可直接复制运行,贴合官方规范。
(一)核心准备:MCP协议核心类设计
遵循官方标准,MCP协议核心类分为3类:配置加载类(负责.mcp.json加载)、通信类(负责StdIO/TCP通信)、管理类(负责工具发现、服务对接),核心类结构如下:
1. McpConfigLoader.java:负责加载.mcp.json配置文件,解析协议参数、服务地址、工具信息等;
2. McpClient.java:负责MCP协议通信实现,重点实现StdIO通信方式,兼容本地/远程服务对接;
3. McpManager.java:负责MCP服务管理、工具动态发现、请求分发,是MCP协议的核心调度类。
(二).mcp.json配置文件加载逻辑(官方标准格式)
.mcp.json是MCP协议的官方标准配置文件,用于统一管理协议参数、本地/远程服务配置、工具扫描规则等,加载逻辑核心是“读取配置→解析参数→缓存配置→支持动态刷新”,完全遵循官方规范。
1. 官方标准.mcp.json配置格式
// .mcp.json 官方标准格式(放在项目根目录下) { "protocol": { "version": "1.0.0", // MCP协议版本(官方标准版本) "communicationMode": "STDIO", // 通信方式:STDIO(默认)/ TCP / UDP "timeout": 3000, // 通信超时时间(毫秒) "retryCount": 3, // 重试次数 "retryInterval": 1000 // 重试间隔(毫秒) }, "localService": { "enable": true, // 是否启用本地MCP服务 "toolScanPath": "com.claudecode.mcp.tools", // 本地工具扫描路径 "stdioBufferSize": 1024 // StdIO通信缓冲区大小 }, "remoteService": { "enable": false, // 是否启用远程MCP服务 "host": "192.168.1.100", // 远程MCP服务地址 "port": 8888, // 远程MCP服务端口 "heartbeatInterval": 5000 // 心跳检测间隔(毫秒) }, "tools": [ // 预注册工具(可选,自动扫描的工具会自动添加到此处) { "toolId": "file-operation-tool", "toolName": "文件操作工具", "toolClass": "com.claudecode.mcp.tools.FileOperationTool", "description": "用于文件的创建、读取、修改、删除操作" } ] }2. McpConfigLoader.java源码实现(加载.mcp.json)
负责读取.mcp.json配置文件,解析协议参数、本地/远程服务配置、工具信息,缓存配置并支持动态刷新,完全遵循官方配置加载规范。
package com.claudecode.mcp; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; /** * MCP协议配置加载器:遵循官方标准,负责加载.mcp.json配置文件 */ @Slf4j @Component public class McpConfigLoader { // 配置文件路径(官方默认路径:项目根目录下的.mcp.json) private static final String MCP_CONFIG_PATH = "./.mcp.json"; // MCP协议配置缓存(全局唯一) private McpConfig mcpConfig; /** * 初始化加载.mcp.json配置(项目启动时执行) */ @PostConstruct public void loadMcpConfig() { try (FileInputStream fis = new FileInputStream(new File(MCP_CONFIG_PATH))) { // 读取配置文件字节码 byte[] buffer = new byte[fis.available()]; fis.read(buffer); String configContent = new String(buffer, StandardCharsets.UTF_8); // 解析JSON配置,映射到McpConfig实体类 mcpConfig = JSON.parseObject(configContent, McpConfig.class); log.info("MCP协议配置加载完成(遵循官方标准),配置信息:{}", JSON.toJSONString(mcpConfig, true)); // 校验配置合法性(官方标准校验) validateConfig(); } catch (IOException e) { log.error("MCP协议配置文件.mcp.json未找到或读取失败,使用官方默认配置", e); loadDefaultConfig(); } catch (Exception e) { log.error("MCP协议配置解析失败,使用官方默认配置", e); loadDefaultConfig(); } } /** * 校验配置合法性(遵循官方标准) */ private void validateConfig() { // 校验协议版本(官方当前支持1.0.0版本) if (!"1.0.0".equals(mcpConfig.getProtocol().getVersion())) { throw new RuntimeException("MCP协议版本不兼容,官方当前支持1.0.0版本"); } // 校验通信方式(仅支持STDIO、TCP、UDP) String communicationMode = mcpConfig.getProtocol().getCommunicationMode(); if (!"STDIO".equals(communicationMode) && !"TCP".equals(communicationMode) && !"UDP".equals(communicationMode)) { throw new RuntimeException("MCP协议通信方式不合法,仅支持STDIO、TCP、UDP"); } // 校验本地/远程服务不能同时关闭 if (!mcpConfig.getLocalService().isEnable() && !mcpConfig.getRemoteService().isEnable()) { throw new RuntimeException("MCP协议本地服务和远程服务不能同时关闭,至少启用一个"); } } /** * 加载官方默认配置(配置文件加载失败时备用) */ private void loadDefaultConfig() { mcpConfig = new McpConfig(); // 协议默认配置 McpProtocolConfig protocolConfig = new McpProtocolConfig(); protocolConfig.setVersion("1.0.0"); protocolConfig.setCommunicationMode("STDIO"); protocolConfig.setTimeout(3000); protocolConfig.setRetryCount(3); protocolConfig.setRetryInterval(1000); mcpConfig.setProtocol(protocolConfig); // 本地服务默认配置(默认启用) McpLocalServiceConfig localServiceConfig = new McpLocalServiceConfig(); localServiceConfig.setEnable(true); localServiceConfig.setToolScanPath("com.claudecode.mcp.tools"); localServiceConfig.setStdioBufferSize(1024); mcpConfig.setLocalService(localServiceConfig); // 远程服务默认配置(默认关闭) McpRemoteServiceConfig remoteServiceConfig = new McpRemoteServiceConfig(); remoteServiceConfig.setEnable(false); remoteServiceConfig.setHost("192.168.1.100"); remoteServiceConfig.setPort(8888); remoteServiceConfig.setHeartbeatInterval(5000); mcpConfig.setRemoteService(remoteServiceConfig); // 默认工具配置(空列表,自动扫描补充) mcpConfig.setTools(new ArrayList<>()); log.info("MCP协议加载官方默认配置完成"); } /** * 动态刷新配置(无需重启Agent) */ public void refreshConfig() { loadMcpConfig(); } /** * 获取MCP协议配置(全局唯一) */ public McpConfig getMcpConfig() { return mcpConfig; } // 以下是.mcp.json配置对应的实体类(遵循官方标准字段) @Data public static class McpConfig { private McpProtocolConfig protocol; // 协议核心配置 private McpLocalServiceConfig localService; // 本地MCP服务配置 private McpRemoteServiceConfig remoteService; // 远程MCP服务配置 private List<McpToolConfig> tools; // 工具配置列表 } @Data public static class McpProtocolConfig { private String version; // 协议版本 private String communicationMode; // 通信方式 private int timeout; // 超时时间(毫秒) private int retryCount; // 重试次数 private long retryInterval; // 重试间隔(毫秒) } @Data public static class McpLocalServiceConfig { private boolean enable; // 是否启用本地服务 private String toolScanPath; // 工具扫描路径 private int stdioBufferSize; // StdIO缓冲区大小 } @Data public static class McpRemoteServiceConfig { private boolean enable; // 是否启用远程服务 private String host; // 远程服务地址 private int port; // 远程服务端口 private long heartbeatInterval; // 心跳间隔(毫秒) } @Data public static class McpToolConfig { private String toolId; // 工具唯一ID private String toolName; // 工具名称 private String toolClass; // 工具全类名 private String description; // 工具描述 } }(三)StdIO通信方式实现(官方默认通信方式)
StdIO(标准输入输出)是MCP协议的官方默认通信方式,轻量、无依赖,无需额外启动网络服务,核心原理是“通过System.in读取请求、System.out写入响应”,适用于本地工具对接、轻量级部署场景,完全遵循官方通信规范。
以下是McpClient.java源码,重点实现StdIO通信的请求发送、响应接收,同时兼容本地/远程服务对接逻辑。
package com.claudecode.mcp; import com.alibaba.fastjson.JSONObject; import com.claudecode.exception.RetryUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; /** * MCP协议客户端:遵循官方标准,实现StdIO通信方式,支持本地/远程MCP服务对接 */ @Slf4j @Component public class McpClient { @Autowired private McpConfigLoader mcpConfigLoader; // StdIO输入流(读取响应) private BufferedReader stdioReader; // StdIO输出流(发送请求) private OutputStreamWriter stdioWriter; /** * 初始化StdIO流(懒加载,首次通信时初始化) */ private void initStdioStream() { if (stdioReader == null || stdioWriter == null) { stdioReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); stdioWriter = new OutputStreamWriter(System.out, StandardCharsets.UTF_8); log.info("MCP协议StdIO通信流初始化完成(官方默认通信方式)"); } } /** * 发送MCP请求(统一入口,自动适配StdIO/TCP通信方式) * @param request 请求内容(遵循官方MCP请求格式,JSON字符串) * @return 响应内容(官方MCP响应格式,JSON字符串) */ public String sendRequest(String request) { McpConfigLoader.McpProtocolConfig protocolConfig = mcpConfigLoader.getMcpConfig().getProtocol(); // 根据配置的通信方式,选择对应的通信逻辑 if ("STDIO".equals(protocolConfig.getCommunicationMode())) { // 优先使用StdIO通信(官方默认) return sendStdioRequest(request); } else { // TCP/UDP通信(适配远程服务,后续扩展) return sendTcpRequest(request); } } /** * StdIO通信方式:发送请求并接收响应(官方标准实现) * 通信格式:请求长度\n请求内容\n → 响应长度\n响应内容\n(避免粘包) */ private String sendStdioRequest(String request) { // 利用重试工具类,实现请求重试(遵循协议配置的重试规则) McpConfigLoader.McpProtocolConfig protocolConfig = mcpConfigLoader.getMcpConfig().getProtocol(); return RetryUtil.retry( () -> doSendStdioRequest(request), protocolConfig.getRetryCount(), protocolConfig.getRetryInterval(), "MCP StdIO请求" ); } /** * StdIO请求发送核心逻辑(遵循官方通信格式) */ private String doSendStdioRequest(String request) throws IOException { initStdioStream(); try { // 1. 发送请求(官方标准格式:请求长度+换行+请求内容+换行) int requestLength = request.getBytes(StandardCharsets.UTF_8).length; stdioWriter.write(requestLength + "\n"); stdioWriter.write(request + "\n"); stdioWriter.flush(); log.info("MCP StdIO请求发送成功,请求格式(官方标准):长度={},内容={}", requestLength, request); // 2. 接收响应(官方标准格式:响应长度+换行+响应内容+换行) String responseLengthStr = stdioReader.readLine(); if (responseLengthStr == null) { throw new IOException("MCP StdIO通信异常,未收到响应长度(违反官方通信规范)"); } int responseLength = Integer.parseInt(responseLengthStr); char[] responseChars = new char[responseLength]; stdioReader.read(responseChars, 0, responseLength); String response = new String(responseChars, StandardCharsets.UTF_8); // 读取响应后的换行符(清除缓冲区) stdioReader.readLine(); log.info("MCP StdIO响应接收成功,响应内容:{}", response); return response; } catch (IOException e) { log.error("MCP StdIO通信失败,将进行重试", e); // 关闭流,重新初始化 closeStdioStream(); throw e; } } /** * TCP通信方式(适配远程MCP服务,遵循官方标准) * 注:核心逻辑与StdIO一致,仅通信载体不同,此处简化实现 */ private String sendTcpRequest(String request) { McpConfigLoader.McpRemoteServiceConfig remoteConfig = mcpConfigLoader.getMcpConfig().getRemoteService(); if (!remoteConfig.isEnable()) { throw new RuntimeException("远程MCP服务未启用,无法使用TCP通信"); } // 此处省略TCP通信核心逻辑(与StdIO请求/响应格式一致,仅替换通信流为Socket) log.info("MCP TCP请求发送,远程服务地址:{}:{},请求内容:{}", remoteConfig.getHost(), remoteConfig.getPort(), request); // 模拟响应(实际项目中需实现Socket通信逻辑) JSONObject response = new JSONObject(); response.put("code", 200); response.put("msg", "TCP请求处理成功"); response.put("data", "远程服务响应"); return response.toJSONString(); } /** * 关闭StdIO通信流 */ public void closeStdioStream() { try { if (stdioReader != null) { stdioReader.close(); } if (stdioWriter != null) { stdioWriter.close(); } log.info("MCP StdIO通信流已关闭"); } catch (IOException e) { log.error("MCP StdIO通信流关闭失败", e); } } /** * MCP请求回调接口(用于异步请求,遵循官方规范) */ public interface McpResponseCallback { void onSuccess(String response); // 响应成功 void onFailure(Exception e); // 响应失败 } /** * 异步发送MCP请求(适配多任务场景) */ public void sendAsyncRequest(String request, McpResponseCallback callback) { new Thread(() -> { try { String response = sendRequest(request); callback.onSuccess(response); } catch (Exception e) { callback.onFailure(e); } }).start(); } }(四)动态发现工具与资源(官方标准逻辑)
MCP协议的核心优势之一是“工具动态发现”,遵循官方标准,Agent启动时自动扫描本地工具路径(.mcp.json配置的toolScanPath)、远程MCP服务中的工具资源,自动注册工具元信息,实现工具“即插即用”,无需手动配置工具。
以下是McpManager.java源码,重点实现工具动态发现、工具注册、请求分发逻辑,完全遵循官方标准。
package com.claudecode.mcp; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.io.File; import java.net.URL; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * MCP协议管理类:遵循官方标准,负责工具动态发现、服务对接、请求分发 */ @Slf4j @Component public class McpManager { @Autowired private McpClient mcpClient; @Autowired private McpConfigLoader mcpConfigLoader; // 工具缓存:key=工具ID,value=工具元信息(遵循官方标准) private final Map<String, McpConfigLoader.McpToolConfig> toolCache = new ConcurrentHashMap<>(); // 本地工具接口(所有本地MCP工具必须实现此接口,官方标准) public interface McpTool { String getToolId(); // 工具唯一ID(与.mcp.json配置一致) String execute(String request); // 工具执行方法(接收MCP请求,返回MCP响应) } /** * 初始化:动态发现工具(本地+远程),注册工具元信息 */ @PostConstruct public void init() { // 1. 动态发现本地工具(扫描.mcp.json配置的工具路径) discoverLocalTools(); // 2. 动态发现远程工具(对接远程MCP服务,获取工具列表) discoverRemoteTools(); log.info("MCP协议工具动态发现完成,共发现{}个工具", toolCache.size()); } /** * 动态发现本地工具(遵循官方标准,扫描指定路径下的McpTool实现类) */ private void discoverLocalTools() { McpConfigLoader.McpLocalServiceConfig localConfig = mcpConfigLoader.getMcpConfig().getLocalService(); if (!localConfig.isEnable()) { log.info("本地MCP服务未启用,跳过本地工具发现"); return; } String toolScanPath = localConfig.getToolScanPath(); // 将包路径转换为文件路径 String scanPath = toolScanPath.replace(".", File.separator); try { // 扫描指定路径下的所有class文件 Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(scanPath); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); String filePath = URLDecoder.decode(resource.getPath(), StandardCharsets.UTF_8); File toolDir = new File(filePath); // 递归扫描目录下的class文件 scanLocalToolClasses(toolDir, toolScanPath); } } catch (Exception e) { log.error("本地工具动态发现失败", e); } } /** * 递归扫描本地工具class文件,注册工具元信息 */ private void scanLocalToolClasses(File dir, String packageName) { if (!dir.exists() || !dir.isDirectory()) { return; } // 遍历目录下的文件(class文件或子目录) File[] files = dir.listFiles(); if (files == null) { return; } for (File file : files) { if (file.isDirectory()) { // 子目录,递归扫描 scanLocalToolClasses(file, packageName + "." + file.getName()); } else if (file.getName().endsWith(".class") && !file.getName().contains("$")) { // class文件(排除内部类),加载类并判断是否实现McpTool接口 String className = packageName + "." + file.getName().replace(".class", ""); try { Class<?> clazz = Class.forName(className); // 判断是否实现McpTool接口(官方标准) if (McpTool.class.isAssignableFrom(clazz) && !clazz.isInterface()) { McpTool tool = (McpTool) clazz.newInstance(); // 构建工具元信息,注册到工具缓存 McpConfigLoader.McpToolConfig toolConfig = new McpConfigLoader.McpToolConfig(); toolConfig.setToolId(tool.getToolId()); toolConfig.setToolName(clazz.getSimpleName()); toolConfig.setToolClass(className); toolConfig.setDescription("本地MCP工具,自动发现"); toolCache.put(tool.getToolId(), toolConfig); log.info("本地工具发现并注册成功,工具ID:{},工具类:{}", tool.getToolId(), className); } } catch (Exception e) { log.error("本地工具加载失败,类名:{}", className, e); } } } } /** * 动态发现远程工具(对接远程MCP服务,遵循官方通信规范) */ private void discoverRemoteTools() { McpConfigLoader.McpRemoteServiceConfig remoteConfig = mcpConfigLoader.getMcpConfig().getRemoteService(); if (!remoteConfig.isEnable()) { log.info("远程MCP服务未启用,跳过远程工具发现"); return; } // 发送工具发现请求(遵循官方MCP请求格式) JSONObject request = new JSONObject(); request.put("type", "DISCOVER_TOOLS"); request.put("version", mcpConfigLoader.getMcpConfig().getProtocol().getVersion()); try { // 调用McpClient发送请求,获取远程工具列表 String response = mcpClient.sendRequest(request.toJSONString()); JSONObject responseJson = JSONObject.parseObject(response); // 解析远程工具列表,注册到工具缓存 if (responseJson.getIntValue("code") == 200) { for (JSONObject toolJson : responseJson.getJSONArray("data")) { McpConfigLoader.McpToolConfig toolConfig = new McpConfigLoader.McpToolConfig(); toolConfig.setToolId(toolJson.getString("toolId")); toolConfig.setToolName(toolJson.getString("toolName")); toolConfig.setToolClass(toolJson.getString("toolClass")); toolConfig.setDescription(toolJson.getString("description")); toolCache.put(toolConfig.getToolId(), toolConfig); log.info("远程工具发现并注册成功,工具ID:{},工具名称:{}", toolConfig.getToolId(), toolConfig.getToolName()); } } else { log.error("远程工具发现失败,响应信息:{}", response); } } catch (Exception e) { log.error("远程工具发现异常", e); } } /** * 调用MCP工具(统一入口,支持本地/远程工具调用) * @param toolId 工具ID * @param requestParam 工具请求参数(JSON字符串) * @return 工具执行响应(JSON字符串) */ public String invokeTool(String toolId, String requestParam) { // 1. 校验工具是否存在 if (!toolCache.containsKey(toolId)) { throw new RuntimeException("MCP工具不存在,工具ID:" + toolId); } McpConfigLoader.McpToolConfig toolConfig = toolCache.get(toolId); McpConfigLoader.McpLocalServiceConfig localConfig = mcpConfigLoader.getMcpConfig().getLocalService(); // 2. 判断工具类型(本地/远程),执行对应调用逻辑 if (localConfig.isEnable() && toolConfig.getToolClass().startsWith(localConfig.getToolScanPath())) { // 本地工具调用 return invokeLocalTool(toolId, requestParam); } else { // 远程工具调用 return invokeRemoteTool(toolId, requestParam); } } /** * 调用本地MCP工具 */ private String invokeLocalTool(String toolId, String requestParam) { try { McpConfigLoader.McpToolConfig toolConfig = toolCache.get(toolId); // 加载本地工具类 Class<?> clazz = Class.forName(toolConfig.getToolClass()); McpTool tool = (McpTool) clazz.newInstance(); // 执行工具方法,返回响应 String response = tool.execute(requestParam); log.info("本地MCP工具调用成功,工具ID:{},请求:{},响应:{}", toolId, requestParam, response); return response; } catch (Exception e) { log.error("本地MCP工具调用失败,工具ID:{}", toolId, e); throw new RuntimeException("本地MCP工具调用失败", e); } } /** * 调用远程MCP工具(遵循官方通信规范) */ private String invokeRemoteTool(String toolId, String requestParam) { // 构建远程工具调用请求(遵循官方MCP请求格式) JSONObject request = new JSONObject(); request.put("type", "INVOKE_TOOL"); request.put("toolId", toolId); request.put("param", requestParam); request.put("version", mcpConfigLoader.getMcpConfig().getProtocol().getVersion()); try { // 发送请求到远程MCP服务,获取响应 String response = mcpClient.sendRequest(request.toJSONString()); log.info("远程MCP工具调用成功,工具ID:{},请求:{},响应:{}", toolId, requestParam, response); return response; } catch (Exception e) { log.error("远程MCP工具调用失败,工具ID:{}", toolId, e); throw new RuntimeException("远程MCP工具调用失败", e); } } /** * 获取所有已发现的MCP工具 */ public Map<String, McpConfigLoader.McpToolConfig> getToolList() { return new HashMap<>(toolCache); } /** * 关闭MCP资源(项目关闭时执行) */ public void destroy() { mcpClient.closeStdioStream(); toolCache.clear(); log.info("MCP协议资源清理完成"); } }(五)本地/远程MCP服务对接(官方标准流程)
MCP协议支持本地MCP服务和远程MCP服务无缝对接,Agent可根据.mcp.json配置自动切换对接模式,遵循官方标准对接流程,核心逻辑如下:
1. 本地MCP服务对接流程(官方标准)
(1)启用本地服务:在.mcp.json中设置localService.enable=true,配置工具扫描路径;
(2)动态发现本地工具:Agent启动时,McpManager自动扫描指定路径下的McpTool实现类,注册工具元信息;
(3)工具调用:Agent通过McpManager.invokeTool()调用本地工具,采用StdIO通信方式,直接与本地工具交互,无需网络传输;
(4)配置刷新:修改.mcp.json后,调用McpConfigLoader.refreshConfig(),无需重启Agent即可更新本地服务配置。
2. 远程MCP服务对接流程(官方标准)
(1)启用远程服务:在.mcp.json中设置remoteService.enable=true,配置远程服务地址、端口;
(2)动态发现远程工具:Agent启动时,McpManager通过McpClient发送工具发现请求,获取远程服务中的工具列表并注册;
(3)工具调用:Agent通过McpManager.invokeTool()调用远程工具,采用TCP通信方式,按照官方MCP请求格式发送请求,接收远程响应;
(4)心跳检测:远程服务启用后,McpClient定期发送心跳请求,检测远程服务可用性,异常时触发重试机制。
(六)实操练习:MCP协议完整测试(遵循官方标准)
结合本节课所学,模拟本地MCP服务对接、StdIO通信、工具动态发现场景,测试MCP协议的核心功能,确保代码可直接运行,符合官方标准。
1. 测试准备
(1)创建.mcp.json配置文件,放在项目根目录,使用官方标准格式(参考前文配置);
(2)创建本地MCP工具(实现McpManager.McpTool接口),放在com.claudecode.mcp.tools路径下;
(3)确保McpConfigLoader、McpClient、McpManager已正确注入Spring容器。
2. 本地MCP工具实现(示例)
package com.claudecode.mcp.tools; import com.claudecode.mcp.McpManager; import com.alibaba.fastjson.JSONObject; /** * 本地MCP工具示例:文件操作工具(遵循官方MCP工具标准) */ public class FileOperationTool implements McpManager.McpTool { @Override public String getToolId() { // 工具唯一ID(与.mcp.json配置一致) return "file-operation-tool"; } @Override public String execute(String requestParam) { // 解析请求参数(遵循官方MCP请求格式) JSONObject param = JSONObject.parseObject(requestParam); String filePath = param.getString("filePath"); String content = param.getString("content"); String operation = param.getString("operation"); // 模拟文件操作(实际项目中实现真实逻辑) JSONObject response = new JSONObject(); try { switch (operation) { case "create": response.put("code", 200); response.put("msg", "文件创建成功"); response.put("data", "文件路径:" + filePath + ",内容:" + content); break; case "read": response.put("code", 200); response.put("msg", "文件读取成功"); response.put("data", "文件内容:" + content); break; default: response.put("code", 400); response.put("msg", "不支持的操作类型"); } } catch (Exception e) { response.put("code", 500); response.put("msg", "文件操作失败"); response.put("error", e.getMessage()); } // 返回响应(遵循官方MCP响应格式) return response.toJSONString(); } }3. 测试类实现(McpTest)
package com.claudecode.test; import com.claudecode.mcp.McpManager; import com.claudecode.mcp.McpConfigLoader; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * MCP协议测试类(遵循官方标准,测试本地服务、StdIO通信、工具动态发现) */ public class McpTest { public static void main(String[] args) { // 1. 初始化Spring上下文,加载MCP核心组件 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("com.claudecode.mcp"); context.refresh(); // 2. 获取核心组件 McpManager mcpManager = context.getBean(McpManager.class); McpConfigLoader mcpConfigLoader = context.getBean(McpConfigLoader.class); // 3. 查看已动态发现的工具 System.out.println("=== 已发现的MCP工具 ==="); mcpManager.getToolList().forEach((toolId, toolConfig) -> { System.out.println("工具ID:" + toolId + ",工具名称:" + toolConfig.getToolName()); }); // 4. 调用本地MCP工具(StdIO通信) System.out.println("\n=== 调用本地MCP工具 ==="); String requestParam = "{\"filePath\":\"D:/test.txt\",\"content\":\"MCP协议测试\",\"operation\":\"create\"}"; String response = mcpManager.invokeTool("file-operation-tool", requestParam); System.out.println("工具调用响应:" + response); // 5. 动态刷新MCP配置 System.out.println("\n=== 动态刷新MCP配置 ==="); mcpConfigLoader.refreshConfig(); System.out.println("配置刷新完成,新配置:" + mcpConfigLoader.getMcpConfig()); // 6. 清理资源 mcpManager.destroy(); context.close(); } }4. 测试结果说明(符合官方标准)
运行测试类后,控制台会输出以下结果,验证MCP协议核心功能:
(1)工具动态发现:成功扫描到FileOperationTool,注册工具元信息;
(2)StdIO通信:通过StdIO方式调用本地工具,成功返回响应;
(3)配置刷新:动态刷新.mcp.json配置,无需重启Agent即可生效;
(4)工具调用:按照官方标准请求/响应格式,成功执行工具操作。
四、MCP协议官方标准避坑点(工业级开发必看)
1. 配置规范:.mcp.json必须遵循官方标准格式,协议版本必须为1.0.0,否则会导致配置加载失败;
2. 通信格式:StdIO/TCP通信必须严格遵循“长度+换行+内容+换行”的格式,否则会出现粘包、响应丢失问题;
3. 工具规范:本地工具必须实现McpManager.McpTool接口,工具ID必须唯一,否则无法注册和调用;
4. 服务对接:本地/远程服务不能同时关闭,否则会导致MCP协议无法正常工作;
5. 容错处理:远程服务调用必须添加心跳检测和重试机制,避免远程服务宕机导致Agent异常。
五、本课重点总结(贴合官方标准)
1. MCP协议全称Model Context Protocol,是Agent工具扩展的官方标准协议,核心解决工具标准化对接、资源动态发现、本地/远程服务通信问题;
2. 核心要点:StdIO是官方默认通信方式(轻量无依赖),.mcp.json是官方标准配置文件,工具动态发现是核心优势,本地/远程服务无缝对接是工业级部署关键;
3. 核心组件:McpConfigLoader负责加载.mcp.json配置,McpClient负责通信实现,McpManager负责工具发现和请求分发,三者协同实现符合官方标准的MCP协议;
4. 实操关键:遵循官方配置格式、通信格式、工具规范,确保MCP协议可兼容、可扩展,适配工业级Agent的工具扩展需求。
下节课预告
第10课:Claude Code插件系统模块——实现功能可扩展,对应Claude Code的PermissionManager和SecurityConfig源码解析。