手把手带你理解MCP是什么、怎么用、如何开发每个步骤都有详细说明写在前面很多朋友看完MCP的介绍还是一头雾水“这到底是什么跟我有什么关系我该怎么用”别急这篇文章我会用最通俗的方式一步一步带你搞懂MCP。每个概念都会配上生活化的例子每个操作都有完整的代码。第一部分先搞懂“为什么” - 需求分析问题1现在的AI有什么痛点假设你有一个AI助手你想让它帮你读取你电脑上的Excel文件搜索网络上的图片调用公司内部的API现在的问题是每个AI模型都要单独适配ChatGPT写一套代码Claude写另一套本地模型又不一样。太麻烦了问题2MCP怎么解决MCP就像一个万能插座text之前每个电器都要自己的专属插座 → 混乱 现在统一标准什么电器都能插 → 方便MCP就是AI界的USB-C接口让所有AI模型都能用统一的方式调用工具、获取数据。第二部分彻底搞懂MCP - 必知必会什么是MCP用大白话说官方定义MCPModel Context Protocol是一个开放协议用于标准化应用程序向大型语言模型提供上下文的方式。大白话解释MCP是一套通用规则规定了AI怎么“伸手要东西”请求格式工具怎么“把东西给AI”响应格式双方怎么“对话”通信方式MCP架构用餐厅比喻1. 宏观架构把MCP想象成餐厅点餐角色餐厅例子MCP世界顾客你AI模型服务员服务员MCP客户端厨房厨房MCP服务端菜单菜单工具列表流程顾客AI说要吃什么 →服务员MCP客户端记录并传给厨房 →厨房MCP服务端做菜并返回2. SDK 3层架构通俗版text┌─────────────────────────────────────┐ │ 应用层你写代码的地方 │ ← 你只需要关心这层 │ McpTool、McpResource │ ├─────────────────────────────────────┤ │ 协议层MCP自己处理 │ ← 不用你操心 │ 消息格式、交互规则 │ ├─────────────────────────────────────┤ │ 传输层MCP自己处理 │ ← 不用你操心 │ stdio、SSE、HTTP │ └─────────────────────────────────────┘3. MCP客户端谁在用客户端 “请求发起方”实际例子Cursor编辑器Claude Desktop你自己写的Java程序VS Code插件4. MCP服务端谁提供工具服务端 “提供能力的一方”实际例子文件系统服务让AI读写文件数据库服务让AI查询数据图片搜索服务让AI搜图MCP核心概念图解text┌─────────────────────────────────────────────┐ │ MCP服务端 │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Tool │ │Resource │ │ Prompt │ │ │ │ 工具 │ │ 资源 │ │ 提示词 │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ ↓ ↓ ↓ │ │ 可执行操作 可读取数据 可用的模板 │ │ (动词) (名词) (配方) │ └─────────────────────────────────────────────┘详细解释概念通俗理解代码示例Tool工具AI能“做”的事情searchImages(),sendEmail()Resource资源AI能“看”的数据文件、数据库记录、API响应Prompt提示词预设的“对话模板”“你是一个图片搜索专家...”第三部分开始使用MCP实操从这开始第一步环境准备5分钟搞定1.1 安装Node.jsMCP工具依赖bash# Windows: 去官网下载安装包 https://nodejs.org/ # Mac: brew install node # Linux: sudo apt install nodejs npm # 验证安装 node -v # 应该显示 v18.0.0 或更高 npm -v # 显示版本号1.2 安装MCP命令行工具bash# 全局安装MCP CLI npm install -g modelcontextprotocol/cli # 验证安装 mcp --version第二步在Cursor编辑器中使用MCPCursor是什么一个集成了AI的代码编辑器类似VS Code。详细步骤下载Cursor访问 https://cursor.sh/ 下载安装打开设置Windows/Linux:Ctrl ,Mac:Cmd ,找到MCP配置在设置搜索框输入 MCP找到 MCP Servers 配置项添加服务json{ mcpServers: { filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, /path/to/allowed/folder] } } }重启Cursor就可以在AI对话中使用MCP工具了第三步测试MCP是否工作bash# 1. 测试MCP连接 mcp ping # 成功返回: pong # 2. 启动一个简单的MCP服务作为测试 npx -y modelcontextprotocol/server-filesystem /tmp # 3. 在另一个终端列出工具 mcp tools list --server http://localhost:3000第四步在程序中使用MCPPython示例python# 1. 安装Python SDK pip install mcp # 2. 创建测试脚本 test_mcp.py import asyncio from mcp import ClientSession, StdioServerParameters async def main(): # 连接到MCP服务 server_params StdioServerParameters( commandnpx, args[-y, modelcontextprotocol/server-filesystem, /tmp] ) async with ClientSession(server_params) as session: # 初始化连接 await session.initialize() # 列出所有可用工具 tools await session.list_tools() print(可用工具:, [tool.name for tool in tools]) # 调用一个工具 result await session.call_tool( read_file, arguments{path: /tmp/test.txt} ) print(结果:, result) # 运行 asyncio.run(main())bash# 执行脚本 python test_mcp.py第四部分Spring AI MCP开发Java/Spring Boot如果你用的是Java技术栈这部分是你的重点MCP客户端开发调用别人的服务步骤1创建Spring Boot项目在 start.spring.io 创建项目选择Spring Web添加MCP依赖步骤2添加依赖pom.xmlxmlparent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.0/version /parent dependencies !-- Spring Boot基础 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MCP客户端 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-client-spring-boot-starter/artifactId version1.0.0-M1/version /dependency /dependencies步骤3配置文件application.ymlyamlspring: ai: mcp: client: enabled: true # 要连接的MCP服务地址 server-url: http://localhost:8080 # 连接超时毫秒 connect-timeout: 30000 # 请求超时毫秒 request-timeout: 60000 logging: level: org.springframework.ai: DEBUG步骤4编写客户端代码javapackage com.example.mcpclient; import org.springframework.ai.mcp.McpClient; import org.springframework.ai.mcp.model.McpCallToolRequest; import org.springframework.ai.mcp.model.McpCallToolResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; RestController RequestMapping(/api/mcp) public class McpClientController { Autowired private McpClient mcpClient; GetMapping(/search) public String searchImages(RequestParam String keyword) { // 1. 构造请求 McpCallToolRequest request new McpCallToolRequest(); request.setName(image-search); // 要调用的工具名 MapString, Object args new HashMap(); args.put(keyword, keyword); args.put(limit, 5); request.setArguments(args); // 2. 发送请求 McpCallToolResult result mcpClient.callTool(request); // 3. 返回结果 return result.getContent().toString(); } GetMapping(/tools) public ListString listAvailableTools() { // 获取所有可用工具 return mcpClient.listTools() .stream() .map(tool - tool.getName()) .collect(Collectors.toList()); } }MCP服务端开发提供给别人调用步骤1创建服务端项目同样的方式创建Spring Boot项目添加服务端依赖xmldependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-server-spring-boot-starter/artifactId version1.0.0-M1/version /dependency步骤2配置文件yamlspring: ai: mcp: server: name: my-image-search-service version: 1.0.0 # 传输方式stdio标准输入输出或 sseHTTP transport-type: sse # HTTP端口使用SSE时 port: 8080 server: port: 8080步骤3启用MCP服务javapackage com.example.mcpserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.ai.mcp.server.annotation.EnableMcpServer; SpringBootApplication EnableMcpServer // 这个注解启用MCP服务能力 public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); System.out.println(MCP服务已启动地址: http://localhost:8080); } }步骤4开发MCP工具javapackage com.example.mcpserver; import org.springframework.ai.mcp.server.annotation.McpTool; import org.springframework.ai.mcp.server.annotation.McpToolParam; import org.springframework.stereotype.Service; import lombok.extern.slf4j.Slf4j; import java.util.List; import java.util.ArrayList; Service Slf4j public class ImageSearchService { /** * 搜索图片的工具 * McpTool 注解把这个方法暴露为MCP工具 */ McpTool( name image-search, description 根据关键词搜索图片返回图片URL列表 ) public ListImageInfo searchImages( McpToolParam(description 搜索关键词比如风景、猫、汽车) String keyword, McpToolParam(description 返回图片数量默认10张最大50) Integer limit ) { log.info(收到图片搜索请求: keyword{}, limit{}, keyword, limit); // 限制最大数量 if (limit null || limit 50) { limit 10; } // 这里是示例数据实际可以调用Unsplash、Pexels等API ListImageInfo results new ArrayList(); for (int i 0; i limit; i) { ImageInfo image new ImageInfo(); image.setId(String.valueOf(i)); image.setTitle(keyword - 图片 (i1)); image.setUrl(https://example.com/images/ keyword _ i .jpg); image.setThumbnail(https://example.com/thumbnails/ keyword _ i .jpg); results.add(image); } return results; } /** * 获取最近上传的图片 * McpResource 注解暴露资源 */ McpResource(uri image://recent/{count}) public ListImageInfo getRecentImages(McpResourcePath String count) { int num Integer.parseInt(count); return searchImages(recent, num); } } // 数据类 class ImageInfo { private String id; private String title; private String url; private String thumbnail; // getter/setter 省略 }步骤5运行服务bash# 打包 mvn clean package # 运行 java -jar target/mcp-server-1.0.0.jar服务启动后访问http://localhost:8080可以看到MCP服务信息。第五部分完整实战 - 图片搜索服务复制就能用服务端完整代码ImageSearchService.javajavapackage com.example.imagesearch; import org.springframework.ai.mcp.server.annotation.McpTool; import org.springframework.ai.mcp.server.annotation.McpToolParam; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.JsonNode; import java.util.*; Service public class ImageSearchService { private final RestTemplate restTemplate new RestTemplate(); McpTool(name search-images, description 从Unsplash搜索免费图片) public ListMapString, String searchImages( McpToolParam(description 搜索关键词如mountain, cat, car) String keyword, McpToolParam(description 返回数量默认5) Integer limit ) { // 调用Unsplash API免费图片API String url https://api.unsplash.com/search/photos?query keyword per_page (limit null ? 5 : limit) client_idYOUR_UNSPLASH_ACCESS_KEY; try { JsonNode response restTemplate.getForObject(url, JsonNode.class); ListMapString, String results new ArrayList(); for (JsonNode photo : response.get(results)) { MapString, String image new HashMap(); image.put(id, photo.get(id).asText()); image.put(description, photo.get(description) ! null ? photo.get(description).asText() : keyword); image.put(url, photo.get(urls).get(regular).asText()); image.put(thumbnail, photo.get(urls).get(thumb).asText()); image.put(author, photo.get(user).get(name).asText()); results.add(image); } return results; } catch (Exception e) { // 返回模拟数据 return getMockData(keyword, limit); } } private ListMapString, String getMockData(String keyword, Integer limit) { ListMapString, String results new ArrayList(); for (int i 0; i (limit null ? 5 : limit); i) { MapString, String image new HashMap(); image.put(id, mock_ i); image.put(description, keyword 图片 (i1)); image.put(url, https://picsum.photos/id/ (i10) /800/600); image.put(thumbnail, https://picsum.photos/id/ (i10) /200/150); results.add(image); } return results; } }客户端完整代码ImageSearchController.javajavapackage com.example.imageclient; import org.springframework.ai.mcp.McpClient; import org.springframework.ai.mcp.model.McpCallToolRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.*; RestController RequestMapping(/api/images) public class ImageSearchController { Autowired private McpClient mcpClient; GetMapping(/search) public MapString, Object search(RequestParam String q, RequestParam(defaultValue 5) int limit) { MapString, Object response new HashMap(); response.put(keyword, q); response.put(limit, limit); try { // 调用MCP服务 McpCallToolRequest request new McpCallToolRequest(); request.setName(search-images); MapString, Object args new HashMap(); args.put(keyword, q); args.put(limit, limit); request.setArguments(args); Object result mcpClient.callTool(request); response.put(success, true); response.put(data, result); response.put(message, 搜索成功); } catch (Exception e) { response.put(success, false); response.put(message, 搜索失败: e.getMessage()); } return response; } }第六部分最佳实践避坑指南1. 工具设计原则java// ❌ 错误一个工具做太多事 McpTool(name doEverything) public String doEverything(String action, String param1, String param2, ...) // ✅ 正确每个工具职责单一 McpTool(name searchImages) public ListImage searchImages(String keyword) McpTool(name downloadImage) public String downloadImage(String imageId) McpTool(name getImageInfo) public ImageInfo getImageInfo(String imageId)2. 参数设计java// ❌ 错误参数含义模糊 McpTool(name process) public String process(String p1, String p2) // ✅ 正确参数清晰且有描述 McpTool(name searchImages, description 搜索图片) public ListImage searchImages( McpToolParam(description 搜索关键词如风景、猫) String keyword, McpToolParam(description 返回数量1-50默认10) Integer limit, McpToolParam(description 排序方式relevance/popularity/latest) String sortBy )3. 错误处理javaMcpTool(name searchImages) public ListImage searchImages(String keyword, Integer limit) { // 参数校验 if (keyword null || keyword.trim().isEmpty()) { throw new IllegalArgumentException(关键词不能为空); } if (limit ! null (limit 1 || limit 100)) { throw new IllegalArgumentException(数量必须在1-100之间); } try { // 业务逻辑 return doSearch(keyword, limit); } catch (Exception e) { log.error(搜索失败, e); // 返回空列表而不是抛异常让AI能继续工作 return Collections.emptyList(); } }第七部分部署方案方案1本地运行开发调试bash# 直接运行JAR java -jar mcp-server-1.0.0.jar # 或使用Maven mvn spring-boot:run方案2Docker部署创建DockerfiledockerfileFROM openjdk:17-jdk-slim COPY target/mcp-server-1.0.0.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, /app.jar]构建和运行bash# 构建镜像 docker build -t mcp-image-search . # 运行容器 docker run -d -p 8080:8080 --name mcp-service mcp-image-search # 查看日志 docker logs mcp-service方案3云平台部署Railway示例注册 Railway.app连接你的GitHub仓库Railway会自动检测Spring Boot项目并部署获得公网URLhttps://your-service.up.railway.app第八部分安全和常见问题安全问题及解决方案风险说明解决方案命令注入恶意参数执行危险命令严格校验输入白名单限制越权访问访问不该访问的资源实现权限校验信息泄露返回敏感数据数据脱敏最小化返回DoS攻击大量请求消耗资源限流熔断安全配置示例javaConfiguration public class McpSecurityConfig { Bean public McpSecurityInterceptor securityInterceptor() { return new McpSecurityInterceptor() { Override public boolean preHandle(String toolName, MapString, Object args) { // 1. 参数长度限制 String keyword (String) args.get(keyword); if (keyword ! null keyword.length() 100) { throw new SecurityException(参数过长); } // 2. 敏感词过滤 if (containsSensitiveWords(keyword)) { throw new SecurityException(包含敏感词); } // 3. 频率限制 if (isRateLimitExceeded()) { throw new SecurityException(请求过于频繁); } return true; } }; } }