内容
# MCP 解密:它究竟是如何工作的
## 介绍
你可能听说过模型上下文协议(Model Context Protocol,MCP)——一种标准化的方式,让大型语言模型(LLMs)与外部系统进行交互。但这在底层是如何工作的呢?
大多数工程师都理解 REST APIs、GraphQL 和 HTTP。MCP 则有所不同,如果你和我一样,可能会想:“传输是什么?发现是如何工作的?核心原语是什么?”
本文将通过解释 MCP 在协议层面的具体工作原理,结合你今天可以运行的实际示例,来解密 MCP。
## MCP 实际上是什么
**将 MCP 视为专为 AI 交互设计的基于 stdio 的 JSON-RPC。** 你的 MCP 服务器充当 Claude 与你现有系统之间的协议桥梁。
```
Claude Desktop ←--stdio--→ MCP Server ←--HTTP--→ Your REST API ←--→ Database
(客户端) (协议桥梁) (业务逻辑) (数据)
```
### 关键见解
**进程通信**:MCP 服务器作为子进程生成,通过 stdin/stdout 进行通信。这消除了网络配置,同时允许你的服务器对现有 API 进行正常的 HTTP 调用。
**无需后端更改**:你不需要修改现有的后端系统。你的 REST API、数据库架构和业务逻辑保持完全不变。MCP 只是增加了一层薄薄的翻译层。
## 三个核心原语
MCP 明确定义了三种类型的能力,映射到熟悉的 API 模式:
### 1. 工具(函数调用)
- **目的**:Claude 可以执行的操作
- **控制**:Claude 自主决定何时调用它们
- **API 类比**:改变状态的 POST/PUT/DELETE 端点
- **使用场景**:创建记录、发送电子邮件、触发工作流
```python
@mcp.tool()
async def create_support_ticket(title: str, description: str, priority: str) -> str:
"""在我们的系统中创建一个新的支持票据"""
async with httpx.AsyncClient() as client:
response = await client.post(f"{API_BASE}/tickets",
headers={"Authorization": f"Bearer {API_TOKEN}"},
json={
"title": title,
"description": description,
"priority": priority,
"status": "open"
})
ticket = response.json()
return f"创建的票据 #{ticket['id']}: {ticket['title']}"
```
### 2. 资源(数据访问)
- **目的**:Claude 可以读取的上下文信息
- **控制**:Claude 在需要背景信息时请求
- **API 类比**:提供只读数据的 GET 端点
- **使用场景**:用户资料、配置数据、文档
```python
@mcp.resource("tickets://recent")
async def get_recent_tickets() -> str:
"""获取最近的支持票据以供参考"""
async with httpx.AsyncClient() as client:
response = await client.get(f"{API_BASE}/tickets/recent",
headers={"Authorization": f"Bearer {API_TOKEN}"})
tickets = response.json()
# 为 Claude 的消费格式化
summary = "最近的支持票据:\n"
for ticket in tickets:
summary += f"- #{ticket['id']}: {ticket['title']} ({ticket['status']})\n"
return summary
```
### 3. 提示(模板)
- **目的**:与数据的结构化交互模式
- **控制**:用户通过 Claude 的 UI 明确调用它们
- **API 类比**:参数化报告生成器
- **使用场景**:分析工作流、报告模板、引导交互
```python
@mcp.prompt()
async def customer_health_check(customer_id: str) -> str:
"""生成全面的客户健康分析"""
async with httpx.AsyncClient() as client:
# 从多个端点收集数据
customer = await client.get(f"{API_BASE}/customers/{customer_id}")
tickets = await client.get(f"{API_BASE}/customers/{customer_id}/tickets")
usage = await client.get(f"{API_BASE}/customers/{customer_id}/usage")
return f"""分析该客户的健康状况:
**客户资料:**
{json.dumps(customer.json(), indent=2)}
**最近的支持活动:**
{json.dumps(tickets.json(), indent=2)}
**使用指标:**
{json.dumps(usage.json(), indent=2)}
请提供健康评分(1-10)和可行的建议。"""
```
## 协议是如何工作的
### 架构堆栈
```
┌─────────────────────────────────────┐
│ 你的业务逻辑与 HTTP APIs │ ← 不变的现有系统
├─────────────────────────────────────┤
│ MCP 方法(工具、资源) │ ← 你的服务器实现
├─────────────────────────────────────┤
│ JSON-RPC 2.0 消息格式 │ ← 协议规范
├─────────────────────────────────────┤
│ stdio 传输(管道) │ ← 进程通信
└─────────────────────────────────────┘
```
- **传输层**:Claude 与你的服务器进程之间的 stdin/stdout 管道
- **协议层**:用于结构化请求/响应消息的 JSON-RPC 2.0
- **应用层**:你的服务器将 MCP 调用转换为 HTTP API 调用
- **业务层**:你现有的 REST APIs 和数据库保持不变
### 发现协议:确切的顺序
当 Claude 启动你的 MCP 服务器时,会发生以下情况:
**步骤 1:进程生成**
```bash
Claude 执行:python /path/to/your/server.py
```
**步骤 2:握手**
```
- Claude: "我是 Claude Desktop v1.0,你能做什么?"
- 你的服务器: "我是 WeatherAPI Bridge v1.0,我可以调用天气工具并提供配置数据"
```
**步骤 3:工具发现**
```
- Claude: "你有哪些函数?"
- 你的服务器: "我有 get_weather(city) 和 send_alert(message, urgency)"
```
**步骤 4:资源发现**
```
- Claude: "你能提供什么数据?"
- 你的服务器: "我可以提供 config://app 的当前配置和 users://active 的用户数据"
```
**步骤 5:运行时使用**
```
- Claude: "执行 get_weather,城市=Tokyo"
- 你的服务器: 发起 HTTP 调用到 `POST /api/weather` → 返回格式化结果
```
## 为什么这种设计有效
**进程隔离**:每个 MCP 服务器在自己的进程中运行,环境受控
**简单传输**:stdio 消除了网络配置和安全问题
**熟悉的模式**:JSON-RPC 是一个成熟的标准,拥有强大的工具支持
**最小更改**:你现有的 APIs 和基础设施保持完全不变
**默认安全**:没有暴露的端口,身份验证在 API 层处理
## 快速入门
MCP 的美妙之处在于 **你的后端不会改变**。你的 REST API、数据库和业务逻辑保持完全不变。你只需添加一个薄薄的 MCP 桥,将 Claude 的请求与 API 调用进行翻译。
这种设计使你能够在不进行架构更改的情况下,将任何现有系统暴露给 Claude——只需用 MCP 工具和资源包装你的 APIs。
## 资源
- [MCP 规范](https://spec.modelcontextprotocol.io/)
- [官方 Python SDK](https://github.com/modelcontextprotocol/python-sdk)