深入浅出MCP:从零开始的完整学习指南(保姆级教程)
很多朋友看完MCP的介绍还是一头雾水:“这到底是什么?跟我有什么关系?我该怎么用?别急,这篇文章我会用最通俗的方式一步一步带你搞懂MCP。每个概念都会配上生活化的例子,每个操作都有完整的代码。官方定义:MCP(Model Context Protocol)是一个开放协议,用于标准化应用程序向大型语言模型提供上下文的方式。大白话解释:MCP是一套通用规则,规定了:AI怎么“伸手要东西”(请求格式)工
手把手带你理解MCP是什么、怎么用、如何开发,每个步骤都有详细说明
写在前面
很多朋友看完MCP的介绍还是一头雾水:“这到底是什么?跟我有什么关系?我该怎么用?”
别急,这篇文章我会用最通俗的方式,一步一步带你搞懂MCP。每个概念都会配上生活化的例子,每个操作都有完整的代码。
第一部分:先搞懂“为什么” - 需求分析
问题1:现在的AI有什么痛点?
假设你有一个AI助手,你想让它帮你:
-
读取你电脑上的Excel文件
-
搜索网络上的图片
-
调用公司内部的API
现在的问题是:每个AI模型都要单独适配,ChatGPT写一套代码,Claude写另一套,本地模型又不一样。太麻烦了!
问题2:MCP怎么解决?
MCP就像一个万能插座:
text
之前:每个电器都要自己的专属插座 → 混乱 现在:统一标准,什么电器都能插 → 方便
MCP就是AI界的USB-C接口,让所有AI模型都能用统一的方式调用工具、获取数据。
第二部分:彻底搞懂MCP - 必知必会
什么是MCP?(用大白话说)
官方定义:MCP(Model 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.js(MCP工具依赖)
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编辑器中使用MCP
Cursor是什么? 一个集成了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
第四步:在程序中使用MCP(Python示例)
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(
command="npx",
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.xml)
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<dependencies>
<!-- Spring Boot基础 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MCP客户端 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
<version>1.0.0-M1</version>
</dependency>
</dependencies>
步骤3:配置文件(application.yml)
yaml
spring:
ai:
mcp:
client:
enabled: true
# 要连接的MCP服务地址
server-url: http://localhost:8080
# 连接超时(毫秒)
connect-timeout: 30000
# 请求超时(毫秒)
request-timeout: 60000
logging:
level:
org.springframework.ai: DEBUG
步骤4:编写客户端代码
java
package 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"); // 要调用的工具名
Map<String, 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 List<String> listAvailableTools() {
// 获取所有可用工具
return mcpClient.listTools()
.stream()
.map(tool -> tool.getName())
.collect(Collectors.toList());
}
}
MCP服务端开发(提供给别人调用)
步骤1:创建服务端项目
同样的方式创建Spring Boot项目,添加服务端依赖:
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
<version>1.0.0-M1</version>
</dependency>
步骤2:配置文件
yaml
spring:
ai:
mcp:
server:
name: my-image-search-service
version: 1.0.0
# 传输方式:stdio(标准输入输出)或 sse(HTTP)
transport-type: sse
# HTTP端口(使用SSE时)
port: 8080
server:
port: 8080
步骤3:启用MCP服务
java
package 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工具
java
package 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 List<ImageInfo> 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
List<ImageInfo> results = new ArrayList<>();
for (int i = 0; i < limit; i++) {
ImageInfo image = new ImageInfo();
image.setId(String.valueOf(i));
image.setTitle(keyword + " - 图片" + (i+1));
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 List<ImageInfo> 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.java
java
package 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 List<Map<String, 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_id=YOUR_UNSPLASH_ACCESS_KEY";
try {
JsonNode response = restTemplate.getForObject(url, JsonNode.class);
List<Map<String, String>> results = new ArrayList<>();
for (JsonNode photo : response.get("results")) {
Map<String, 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 List<Map<String, String>> getMockData(String keyword, Integer limit) {
List<Map<String, String>> results = new ArrayList<>();
for (int i = 0; i < (limit == null ? 5 : limit); i++) {
Map<String, String> image = new HashMap<>();
image.put("id", "mock_" + i);
image.put("description", keyword + " 图片 " + (i+1));
image.put("url", "https://picsum.photos/id/" + (i+10) + "/800/600");
image.put("thumbnail", "https://picsum.photos/id/" + (i+10) + "/200/150");
results.add(image);
}
return results;
}
}
客户端完整代码
ImageSearchController.java
java
package 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 Map<String, Object> search(@RequestParam String q,
@RequestParam(defaultValue = "5") int limit) {
Map<String, Object> response = new HashMap<>();
response.put("keyword", q);
response.put("limit", limit);
try {
// 调用MCP服务
McpCallToolRequest request = new McpCallToolRequest();
request.setName("search-images");
Map<String, 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 List<Image> 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 List<Image> searchImages(
@McpToolParam(description = "搜索关键词,如:风景、猫") String keyword,
@McpToolParam(description = "返回数量,1-50,默认10") Integer limit,
@McpToolParam(description = "排序方式:relevance/popularity/latest") String sortBy
)
3. 错误处理
java
@McpTool(name = "searchImages")
public List<Image> 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
方案2:Docker部署
创建 Dockerfile:
dockerfile
FROM 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项目并部署
-
获得公网URL:
https://your-service.up.railway.app
第八部分:安全和常见问题
安全问题及解决方案
| 风险 | 说明 | 解决方案 |
|---|---|---|
| 命令注入 | 恶意参数执行危险命令 | 严格校验输入,白名单限制 |
| 越权访问 | 访问不该访问的资源 | 实现权限校验 |
| 信息泄露 | 返回敏感数据 | 数据脱敏,最小化返回 |
| DoS攻击 | 大量请求消耗资源 | 限流,熔断 |
安全配置示例
java
@Configuration
public class McpSecurityConfig {
@Bean
public McpSecurityInterceptor securityInterceptor() {
return new McpSecurityInterceptor() {
@Override
public boolean preHandle(String toolName, Map<String, 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;
}
};
}
}更多推荐

所有评论(0)