MCP 协议深入解析
MCP 协议深入解析
MCP(Model Context Protocol)是 Anthropic 提出的 AI 工具集成标准协议,被称为 AI 时代的"USB 接口"。2025 年起已成为 Cursor、Claude Desktop、Windsurf 等主流 AI IDE 的事实标准,也是 2026 年 Java AI 工程师面试的高频考点。
写在前面
字节、阿里、腾讯的 AI 岗面试已开始考察 MCP 相关知识。面试官常问:MCP 解决了什么问题?它和 Function Calling 有什么本质区别?MCP Server 的三类能力是什么?如何用 Spring AI 实现一个 MCP Server? 本文系统梳理 MCP 核心原理与 Java 实战,帮你做到知其然更知其所以然。
MCP 是什么,为什么需要它
没有 MCP 之前的痛点
在 MCP 出现之前,每个 AI 应用要集成外部工具,都需要单独适配:
- ChatGPT Plugin 有自己的接口规范
- Claude 有自己的工具集成方式
- Cursor IDE 有自己的工具调用协议
- 企业自研 AI 应用又是另一套实现
结果:N 个 AI 应用 × M 个工具 = N×M 的集成工作量,且给 Claude 写的数据库工具,无法直接给 Cursor 或自研应用使用,工具完全无法复用。
MCP 的价值:N+M 替代 N×M
没有 MCP(碎片化集成):
Claude ──── 数据库适配器 A
Cursor ──── 数据库适配器 B
自研应用 ──── 数据库适配器 C
有了 MCP(标准化集成):
Claude ─┐
Cursor ─┤── MCP Client ──── 数据库 MCP Server(一次开发,处处复用)
自研应用 ─┘类比 USB:USB 出现前每种设备专有接口,USB 出现后一种标准接口连接所有设备。MCP 就是 AI 工具集成领域的 USB 接口。
MCP 于 2024 年 11 月由 Anthropic 开源,2025 年 OpenAI、Google、微软、阿里等主流厂商相继宣布支持,迅速成为行业事实标准。
MCP vs Function Calling 的区别
这是面试最高频的问题,很多人混淆两者。
| 对比维度 | Function Calling | MCP |
|---|---|---|
| 定位 | LLM 调用工具的通信协议(应用内部) | AI 应用与外部工具服务集成的标准协议(跨系统) |
| 作用范围 | 单个 AI 应用内部 | 跨 AI 应用、跨语言、跨团队 |
| 工具复用 | 同一工具代码无法跨应用复用 | 工具一次开发,所有 MCP Host 均可使用 |
| 部署方式 | 工具逻辑与 AI 应用耦合部署 | 工具作为独立 MCP Server 部署,独立维护 |
| 实现语言 | 通常与宿主应用同语言 | 任意语言均可实现 MCP Server |
| 发现能力 | 工具列表在代码中静态定义 | Client 运行时动态发现 Server 提供的所有工具 |
| 典型场景 | Spring AI @Tool 注解、OpenAI tools 参数 | Cursor 连接数据库、Claude Desktop 操作文件系统 |
一句话总结:Function Calling 是 LLM 调用工具的"通话方式",MCP 是工具服务的"标准插槽"——两者是不同层面的东西,MCP Server 内部实现工具时仍然用到 Function Calling 的思想。
MCP Server 架构:三类核心能力
下图展示了 MCP 的标准化集成架构,Host 应用通过统一的 MCP 协议连接多个不同类型的 Server:
MCP Server 向 Host 暴露三类标准能力,外加一个反向能力:
Tools(可调用函数)
最核心的能力,代表 LLM 可以主动触发的操作:
特点:有副作用(写数据库、发邮件、调 API)
触发方:LLM 根据用户意图自主决定是否调用
示例:executeSQL、sendEmail、createGitIssue、callRestAPIResources(可读取内容)
类似文件系统中的只读文件,供 LLM 获取上下文信息:
特点:只读,提供结构化或非结构化内容
触发方:LLM 或 Host 按需读取
示例:数据库 Schema、API 接口文档、配置文件内容、日志片段Prompts(提示词模板)
预定义的提示词片段,可以带参数,供 Host 复用:
特点:可参数化的复用提示词
触发方:Host 在特定场景下调用
示例:代码 Review 规范模板、SQL 优化提示、Bug 分析模板Sampling(反向 LLM 调用)
MCP Server 反向请求 Host 执行 LLM 推理,工具服务无需自持 API Key:
场景:MCP Server 处理工具请求时需要 AI 辅助(如生成摘要)
优势:工具服务无需维护 LLM 连接和 API Key,借用 Host 的 LLM 能力传输层选择
| 传输方式 | 适用场景 | 说明 |
|---|---|---|
| stdio | 本地 IDE 集成 | Client 通过 stdin/stdout 通信,延迟低,不支持远程 |
| Streamable HTTP | 生产环境(推荐) | 2025 年新规范,支持多用户并发,灵活支持流式响应 |
| SSE | 兼容旧系统 | 已被 Streamable HTTP 取代,仍广泛兼容 |
Java 实现 MCP Server 示例代码
以下用 Spring AI + MCP Java SDK 实现一个业务数据查询 MCP Server。
Maven 依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.0</version>
</parent>
<dependencies>
<!-- Spring AI MCP Server Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>
<!-- HTTP 传输(生产推荐) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>application.yml
spring:
application:
name: business-data-mcp-server
ai:
mcp:
server:
name: 业务数据查询服务
version: 1.0.0
type: SYNC
transport: HTTPSSE # 生产用 HTTP;本地 IDE 用 STDIO
instructions: |
提供对业务数据库的只读查询能力。
支持:查询销售数据、库存信息、客户信息、查看表结构。
限制:只允许 SELECT 查询,不允许修改数据。
server:
port: 8080MCP Server 工具实现
@Service
@Slf4j
public class DatabaseMcpTools {
private final JdbcTemplate jdbcTemplate;
private final ObjectMapper objectMapper;
// 安全白名单:只允许查询这些表
private static final Set<String> ALLOWED_TABLES = Set.of(
"orders", "products", "customers", "inventory"
);
/**
* Tool 1:执行业务数据查询
*/
@Tool(description = "在业务数据库中执行 SELECT 查询,返回 JSON 数据。只允许查询白名单内的表。")
public String executeQuery(
@ToolParam(description = "SQL SELECT 语句") String sql,
@ToolParam(description = "最大返回行数,默认 50,上限 500") Integer limit) {
String trimmed = sql.trim().toLowerCase();
// 安全校验:只允许 SELECT
if (!trimmed.startsWith("select")) {
return "安全限制:只允许 SELECT 查询。";
}
// 安全校验:白名单表名
boolean hasAllowedTable = ALLOWED_TABLES.stream()
.anyMatch(table -> trimmed.contains(table));
if (!hasAllowedTable) {
return "安全限制:只允许查询以下表:" + ALLOWED_TABLES;
}
// 安全校验:禁止危险关键词
List<String> dangerKeywords = List.of("drop", "delete", "update", "insert", "alter");
for (String kw : dangerKeywords) {
if (trimmed.contains(kw)) {
return "安全限制:查询包含非法关键词:" + kw;
}
}
try {
int maxLimit = Math.min(limit != null ? limit : 50, 500);
String safeSql = sql.trim().replaceAll(";\\s*$", "") + " LIMIT " + maxLimit;
List<Map<String, Object>> results = jdbcTemplate.queryForList(safeSql);
log.info("MCP executeQuery: {} 条结果", results.size());
return objectMapper.writeValueAsString(results);
} catch (Exception e) {
log.error("SQL 查询失败: {}", sql, e);
return "查询失败:" + e.getMessage();
}
}
/**
* Tool 2:查看表结构(Resource 概念的 Tool 形式实现)
*/
@Tool(description = "查看指定表的列名、数据类型和注释,用于了解数据结构再生成 SQL")
public String describeTable(
@ToolParam(description = "表名,如:orders、products") String tableName) {
if (!ALLOWED_TABLES.contains(tableName.toLowerCase())) {
return "只允许查看以下表:" + ALLOWED_TABLES;
}
try {
List<Map<String, Object>> columns = jdbcTemplate.queryForList(
"SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE " +
"FROM INFORMATION_SCHEMA.COLUMNS " +
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? " +
"ORDER BY ORDINAL_POSITION",
tableName
);
return objectMapper.writeValueAsString(columns);
} catch (Exception e) {
return "查询表结构失败:" + e.getMessage();
}
}
/**
* Tool 3:列出所有可用表(Prompt/引导类能力)
*/
@Tool(description = "列出所有可查询的业务数据表及其说明,查询前应先调用此工具了解有哪些数据")
public String listAvailableTables() {
return """
可用表:
- orders:订单表(订单号、金额、状态、用户ID、创建时间)
- products:商品表(商品名称、价格、分类、库存数量)
- customers:客户表(客户名称、注册时间、等级、联系方式)
- inventory:库存表(商品ID、仓库、库存数量、最后更新时间)
""";
}
}在 Cursor 中配置使用
在项目目录创建 .cursor/mcp.json:
{
"mcpServers": {
"business-data": {
"url": "http://localhost:8080/sse",
"transport": "sse",
"description": "公司业务数据库查询工具"
}
}
}Claude Desktop 使用 stdio 模式配置(claude_desktop_config.json):
{
"mcpServers": {
"business-data": {
"command": "java",
"args": ["-jar", "/path/to/business-mcp-server.jar"],
"env": { "DB_USER": "user", "DB_PASS": "password" }
}
}
}国内大厂使用 MCP 的场景
阿里巴巴:通义 AI 平台(百炼)已全面支持 MCP,开发者可以将自定义 MCP Server 接入通义千问模型。阿里云内部将 MCP 用于 AI 客服工具链,连接订单系统、库存系统等业务系统,实现"一个 Agent 处理跨系统业务查询"。
腾讯:腾讯云 AI Agent 平台(元器)支持 MCP 协议,微信团队将 MCP 用于企业微信机器人与内部知识库、OA 系统的标准化集成,减少重复开发工作。
字节跳动:Trae IDE(字节 AI 编程工具)原生支持 MCP,内部 AI 效能平台用 MCP Server 将 Lark(飞书)文档、代码仓库、监控系统接入 AI 工具链,工程师可以用自然语言查询线上告警并联动代码库分析原因。
共同趋势:大厂将 MCP 作为 AI 工具集成的基础设施层,把原来碎片化的 AI 集成统一为标准化的 MCP Server 生态,减少 N×M 的集成成本,让每个业务系统只需维护一个 MCP Server 实现,即可接入全公司所有 AI 应用。
高频面试题
Q1:MCP 协议解决了什么问题?
MCP 解决了 AI 工具集成的碎片化问题。没有 MCP 之前,每个 AI 应用集成每个外部工具都需要单独适配,N 个应用 × M 个工具 = N×M 的工作量,且工具无法跨应用复用。MCP 统一了工具集成协议标准,工具只需实现一次 MCP Server,所有支持 MCP 的 AI 应用都能直接使用,将工作量降为 N+M,并且工具可以独立部署、独立维护、跨团队共享。
Q2:MCP 和 Function Calling 有什么本质区别?
Function Calling 是 LLM 与工具通信的协议(应用内部),描述 LLM "怎么调用工具";MCP 是 AI 应用与外部工具服务之间的集成标准(跨系统),描述工具服务"怎么被所有 AI 应用发现和使用"。两者不互斥:MCP Server 内部实现工具时,仍然利用了 Function Calling 的思路来定义工具的入参/出参;而 MCP 解决的是工具的"标准化打包和跨应用分发"问题,Function Calling 无法解决这一点。
Q3:MCP Server 的 Tools、Resources、Prompts 三类能力各适用于什么场景?
Tools 适合有副作用的操作(写数据、发消息、调 API),LLM 主动决定是否触发;Resources 适合提供只读上下文信息(数据库 Schema、接口文档、配置内容),类似文件系统的读取操作;Prompts 适合封装可复用的提示词模板(Code Review 规范、SQL 优化提示),供 Host 在特定场景复用。三类能力分工不同,一个 MCP Server 可以同时提供多种类型。
Q4:stdio 和 Streamable HTTP 传输方式如何选择?
stdio 适合本地 IDE 集成(Cursor/Claude Desktop),Client 通过标准输入输出与 Server 子进程通信,不支持远程访问和多用户并发;Streamable HTTP 适合生产环境部署,基于 HTTP 支持多用户、支持远程访问,是 2025 年 MCP 新规范推荐的方式。选择原则:个人本地开发用 stdio(零网络配置),企业生产服务用 Streamable HTTP(可扩展、可监控)。
Q5:如何保证 MCP Server 的安全性?
四个层面:1)工具权限最小化,数据库工具只允许 SELECT,文件工具只允许读特定目录;2)输入验证,白名单表名/路径过滤、SQL 危险关键词拦截;3)认证授权,HTTP 模式下加 Bearer Token 或 mTLS,防止未授权调用;4)审计日志,记录所有工具调用的参数和结果,便于安全审计和问题排查。生产 MCP Server 不应将数据库写权限、文件系统写权限等高风险能力暴露给 LLM。
知识星球深度内容
完整大厂面经(含详细答案、最新更新)、AI 项目源码、1v1 简历修改,扫码加入「AI 工程师加速社区」知识星球获取 👉 立即加入
