内容
<div align="center">
# 🔌 模型上下文协议(MCP)
### 开发者构建MCP服务器、客户端、工具、资源和提示指南
[](https://modelcontextprotocol.io)
[](https://www.python.org/)
[]()
[]()
[](https://anthropic.com)
**Anthropic MCP认证课程的个人学习笔记 — 精炼成一个可搜索的参考资料。**
[概述](#-概述) · [架构](#-架构) · [工具](#-工具) · [资源](#-资源) · [提示](#-提示) · [速查表](#-快速参考)
</div>
---
## 📑 目录
| # | 章节 | 您将学习的内容 |
|---|---------|-------------------|
| 1 | [概述](#-概述) | 什么是MCP,为什么存在,解决的问题 |
| 2 | [架构](#-架构) | 客户端 ↔ 服务器拓扑,消息流,传输 |
| 3 | [项目设置](#-项目设置) | CLI聊天机器人项目结构和首次运行 |
| 4 | [定义工具](#-工具) | `@mcp.tool`,类型参数,两个服务器工具 |
| 5 | [MCP检查器](#-服务器检查器) | 用于测试服务器的浏览器内调试器 |
| 6 | [实现客户端](#-客户端实现) | 会话包装器,`list_tools()`,`call_tool()` |
| 7 | [定义资源](#-资源) | 静态和模板URI,MIME类型 |
| 8 | [访问资源](#-访问资源) | `read_resource()`和响应解析 |
| 9 | [定义提示](#-提示-1) | 预先编写,测试指令作为斜杠命令 |
| 10 | [客户端提示](#-客户端提示) | `list_prompts()`和`get_prompt()` |
| 11 | [MCP审查](#-MCP审查) | 工具与资源与提示 — 何时使用什么 |
| 12 | [快速参考](#-快速参考) | 装饰器和SDK调用的速查表 |
---
## 🌟 概述
**模型上下文协议(MCP)** 是一个通信层,为Claude(和其他LLM)提供结构化的上下文和工具访问 — **无需每个开发者为每个服务集成手工编写工具模式。**
### MCP解决的问题
在传统方法中,集成服务的每个开发者都必须:
- ✍️ 手动为每个工具编写JSON模式
- 🔧 编写每个端点的函数实现
- 🔄 维护API演变所需的一切
- 😩 为其他每个服务(Slack,Drive,Postgres…)重复该过程
```
❌ 在MCP之前:您 → 编写工具模式 → 编写函数 → 调用API → 永久维护
✅ 使用MCP:MCP服务器已经公开工具 → 您只需连接您的客户端
```
### 什么是MCP
| 概念 | 定义 |
|---------|-----------|
| **MCP客户端** | 您应用与MCP服务器之间的通信接口 |
| **MCP服务器** | 一个进程,包装外部服务(GitHub,Drive,DB…)并将其功能公开为 **工具**,**资源**和**提示** |
| **传输** | 任意 - 标准输入/标准输出,HTTP,WebSockets — 双方同意 |
| **谁构建服务器?** | 任何人 — 但服务提供商通常会提供官方服务器 |
> 💡 **核心洞察:** MCP将工具定义和执行 *移出* 您的应用程序代码并 *移至* 专用MCP服务器。服务器是外部世界的接口;您的代码只是协调器。
### MCP与工具使用 — 互补而非相同
- **工具使用** = Claude调用函数的能力
- **MCP** = 创建这些函数的 *谁* 和 *如何* 的问题
MCP回答:*“谁是工具的作者?谁运行它?它如何到达Claude?”*
---
## 🏗️ 架构
### 高级拓扑
```mermaid
flowchart LR
User([👤 用户]) -->|查询| App[🖥️ 您的应用/服务器]
App <-->|list_tools / call_tool| Client[🔌 MCP客户端]
Client <-->|JSON-RPC via stdio/HTTP| Server[⚙️ MCP服务器]
Server -->|API调用| External[🌐 外部服务<br/>GitHub · Drive · DB]
style App fill:#1e293b,stroke:#7C3AED,color:#fff
style Client fill:#7C3AED,stroke:#fff,color:#fff
style Server fill:#EC4899,stroke:#fff,color:#fff
style External fill:#0ea5e9,stroke:#fff,color:#fff
```
### 消息流 — 端到端
```mermaid
sequenceDiagram
autonumber
participant U as 👤 用户
participant A as 🖥️ 您的服务器
participant C as 🔌 MCP客户端
participant S as ⚙️ MCP服务器
participant L as 🤖 Claude
participant X as 🌐 外部API
U->>A: "What's in report.pdf?"
A->>C: 获取可用工具
C->>S: list_tools 请求
S-->>C: 工具列表
C-->>A: 工具
A->>L: 查询 + 工具
L-->>A: "call read_doc(doc_id='report.pdf')"
A->>C: call_tool("read_doc", {doc_id})
C->>S: call_tool 请求
S->>X: 读取文件
X-->>S: 内容
S-->>C: 工具结果
C-->>A: 结果
A->>L: 结果
L-->>A: 最终答案
A->>U: 💬 格式化回复
```
### 传输选项
MCP是 **传输无关** 的。客户端和服务器只需要就通道达成一致:
| 传输 | 使用场景 |
|-----------|-------------|
| **标准输入/标准输出** | 两个进程在同一台机器上(本地开发最常见) |
| **HTTP** | 跨网络/跨主机部署 |
| **WebSockets** | 实时,双向,长期会话 |
线路格式 **始终** 是由MCP规范定义的JSON-RPC消息。
### 核心消息类型
| 消息 | 方向 | 目的 |
|---------|-----------|---------|
| `list_tools` 请求/结果 | 客户端 → 服务器 | "您提供哪些工具?" |
| `call_tool` 请求/结果 | 客户端 → 服务器 | "使用这些参数运行此工具" |
| `list_resources` / `read_resource` | 客户端 → 服务器 | 读取应用程序控制的数据 |
| `list_prompts` / `get_prompt` | 客户端 → 服务器 | 获取预写提示模板 |
---
## 🧪 项目设置
课程项目是一个 **基于CLI的聊天机器人** ,实现了自定义MCP客户端和自定义MCP服务器 — 用于教育目的。
> 🔍 **现实世界的注释:** 生产代码通常实现 **一个或另一个** (您的应用要么是消费者,要么是提供者),而不是两者。本项目同时实现两者,以便您可以看到完整的握手。
### 结构
```
mcp-learning/
├── main.py # CLI入口点(运行聊天机器人)
├── mcp_client.py # 自定义MCP客户端类
├── mcp_server.py # 自定义MCP服务器,带有工具
├── .env # ANTHROPIC_API_KEY=...
└── pyproject.toml # uv / pip依赖项
```
### 文档存储 — 仅内存
```python
# 虚假文档 — 在此学习项目中没有磁盘持久性
docs = {
"report.pdf": "Q4收入增长了23%...",
"launch.md": "初始启动目标:9月15日...",
"design.txt": "色彩调色板:靛蓝,板岩,白...",
}
```
### 设置命令
```bash
# 1. 获取启动器
unzip CLI_project.zip
cd mcp-learning
# 2. 添加您的API密钥
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
# 3. 安装依赖项
uv sync # 如果您使用uv
# 或
pip install -r requirements.txt
# 4. 运行
uv run main.py # 使用uv
python main.py # 不使用uv
```
### 首次运行验证
当聊天提示出现时,请使用以下命令进行健康检查:
```
您: what's one plus one
机器人: 2
```
如果您得到答案,则客户端 → 服务器 → Claude的循环已正确连接。
---
## 🛠️ 工具
> **工具** 是 **模型控制** 的原始操作。 **Claude** 决定何时调用它们。
### 思维模型
```
工具 = 您提供给Claude的功能
(例如“运行JavaScript”,“读取文档”,“查询数据库”)
→ 为模型服务
```
### 实现模式(Python SDK)
MCP Python SDK **自动从装饰函数中生成JSON模式**。不再需要手工编写模式。
```python
from mcp.server import FastMCP
from pydantic import Field
mcp = FastMCP("document-server")
# 内存文档存储
docs: dict[str, str] = {
"report.pdf": "Q4收入增长了23%...",
"launch.md": "初始启动目标:9月15日...",
}
```
### 工具 #1 — `read_doc_contents`
```python
@mcp.tool(
name="read_doc_contents",
description="按ID读取文档的全文内容。"
)
def read_doc_contents(doc_id: str = Field(description="要读取的文档ID")) -> str:
"""返回文档文本,如果ID未知则引发异常。"""
if doc_id not in docs:
raise ValueError(f"ID为{doc_id}的文档未找到")
return docs[doc_id]
```
### 工具 #2 — `edit_document`
```python
@mcp.tool(
name="edit_document",
description="在文档中查找并替换字符串。"
)
def edit_document(
doc_id: str = Field(description="要编辑的文档ID"),
old_string: str = Field(description="要查找的确切文本"),
new_string: str = Field(description="替换文本"),
) -> str:
"""应用查找/替换,首先验证文档存在。"""
if doc_id not in docs:
raise ValueError(f"ID为{doc_id}的文档未找到")
docs[doc_id] = docs[doc_id].replace(old_string, new_string)
return f"更新了{doc_id}"
```
### 工具定义的解剖结构
```
@mcp.tool装饰器 ← 标记函数为工具
↓
函数定义 ← 可执行代码
↓
类型参数 ← 成为JSON模式属性
↓
Field(description=...) ← 成为模式的“description”字段
↓
返回类型 ← 成为工具的输出模式
```
### 服务器引导 — 一行代码
```python
if __name__ == "__main__":
mcp.run() # 默认stdio传输
```
### SDK优势
| 手动方法 | MCP SDK方法 |
|-----------------|------------------|
| 为每个工具手工编写JSON模式 | 从Python签名自动生成模式 |
| 手动将每个工具连接到服务器 | `@mcp.tool`装饰器处理注册 |
| 手动格式化输入验证 | 类型提示 + `Field()`为您完成 |
| 模板代码繁重 | 一个文件,几个装饰器,完成 |
---
## 🔍 服务器检查器
**MCP检查器** 是一个浏览器内的调试器,允许您在 **无需连接Claude或您的应用** 的情况下测试MCP服务器。
### 启动
```bash
mcp dev mcp_server.py
```
终端打印一个localhost URL — 在浏览器中打开它。
### 界面游览
```
┌─────────────────────────────────────────────────────────────┐
│ MCP检查器 │
│ │
│ ┌──────────┐ ┌─────────────────────────────────────┐ │
│ │ 连接 │ │ 资源 提示 工具 │ │
│ └──────────┘ └─────────────────────────────────────┘ │
│ │ │ │
│ │ └── 工具面板: │
│ │ • read_doc_contents │
│ │ • edit_document │
│ ▼ │
│ 点击工具 → 右面板: │
│ [doc_id: "report.pdf" ] │
│ [ 运行工具 ] │
│ 输出: "Q4收入增长了23%..." │
└─────────────────────────────────────────────────────────────┘
```
### 工作流程
1. **连接** 到侧边栏中的服务器
2. 点击 **工具** 选项卡
3. 选择一个工具 — 参数字段出现在右侧
4. 填写 → 点击 **运行工具**
5. 检查输出或错误消息
### 为什么它很重要
- ✅ 在集成之前单独测试工具
- ✅ 零仪式迭代工具设计
- ✅ 直观调试参数模式
- ✅ 验证错误路径(尝试缺少的`doc_id`!)
> ⚠️ 检查器UI正在积极开发中 — 期待布局变化,但核心功能保持不变。
---
## 🔌 客户端实现
**客户端** 是SDK会话对象的薄包装。其工作是 **让您的代码其余部分轻松与MCP服务器通信**。
### 为什么使用包装类?
| 原始`ClientSession` | 包装类 |
|---------------------|---------------|
| 手动资源清理 | `async with` / `async enter` / `async exit`处理 |
| SDK类型到处泄露 | 包装器上的干净方法签名 |
| 每个调用站点都冗余 | `client.list_tools()`就足够了 |
### 客户端类
```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
class MCPClient:
def __init__(self, server_params: StdioServerParameters):
self.server_params = server_params
self.session: ClientSession | None = None
self._streams = None
async def connect(self):
"""打开stdio连接并初始化会话。"""
self._streams = await stdio_client(self.server_params).__aenter__()
read, write = self._streams
self.session = await ClientSession(read, write).__aenter__()
await self.session.initialize()
async def cleanup(self):
"""拆除会话和流。"""
if self.session:
await self.session.__aexit__(None, None, None)
if self._streams:
await self._streams.__aexit__(None, None, None)
# ─── 领域方法 ───────────────────────────────────────
async def list_tools(self) -> list:
"""返回服务器提供的工具。"""
result = await self.session.list_tools()
return result.tools
async def call_tool(self, tool_name: str, tool_input: dict) -> str:
"""在服务器上执行工具并返回其结果。"""
result = await self.session.call_tool(tool_name, tool_input)
return result
```
### 工具调用往返
```mermaid
flowchart LR
App[您的应用] -->|1. list_tools| Client[MCPClient]
Client -->|2. 工具列表| App
App -->|3. 将列表发送到Claude| Claude
Claude -->|4. 调用read_doc('x')| App
App -->|5. call_tool| Client
Client -->|6. 结果| App
App -->|7. 结果| Claude
Claude -->|8. 最终答案| App
```
### 典型的端到端循环(伪代码)
```python
async def chat_turn(user_message: str):
# 1. 发现工具
tools = await client.list_tools()
# 2. 询问Claude — 它可能会决定调用工具
response = await claude.messages.create(
model="claude-sonnet-4-5",
tools=tools,
messages=[{"role": "user", "content": user_message}],
)
# 3. 如果Claude想要工具,则执行它
if response.stop_reason == "tool_use":
tool_calls = response.content[-1]
result = await client.call_tool(
tool_calls.name,
tool_calls.input,
)
# 4. 将结果发送回Claude以获取最终答案
...
```
---
## 📚 资源
> **资源** 是 **应用程序控制** 的原始操作。 **您的代码** 决定何时读取它们。
### 思维模型
```
资源 = 您获取到应用程序中的数据
(例如“谷歌云盘文件列表”,“用户配置文件”)
→ 为应用程序服务
```
### 资源类型
| 类型 | URI模式 | 示例 |
|------|-------------|---------|
| **静态/直接** | 固定URI | `docs://documents` |
| **模板化** | 带有`{param}`通配符的URI | `documents/{doc_id}` |
### 资源流
```mermaid
sequenceDiagram
participant App as 🖥️ 应用代码
participant C as 🔌 MCP客户端
participant S as ⚙️ MCP服务器
App->>C: read_resource("documents/report.pdf")
C->>S: read_resource 请求(URI)
S->>S: 匹配URI → 调用资源函数
S-->>C: result.contents
C-->>App: 数据
```
### 定义资源
```python
@mcp.resource(
uri="docs://documents", # 静态
name="所有文档",
description="存储中每个文档的列表。",
mime_type="application/json",
)
def list_documents() -> list[str]:
"""返回所有文档ID。"""
return list(docs.keys())
@mcp.resource(
uri="documents/{doc_id}", # 模板化
name="单个文档",
description="按ID获取单个文档。",
mime_type="text/plain",
)
def read_document(doc_id: str) -> str:
"""URI参数自动成为函数关键字参数。"""
if doc_id not in docs:
raise ValueError(f"ID为{doc_id}的文档未找到")
return docs[doc_id]
```
### 关键实现细节
- 🎯 URI参数(`{doc_id}`)自动成为 **函数关键字参数**
- 📦 SDK **自动序列化** 返回值(字典 → JSON,字符串 → 文本)
- 🏷️ `mime_type` 是 **客户端反序列化的提示** (`application/json`,`text/plain`等)
- 🧩 **每个不同读取操作一个资源** — 不要将列表和获取合并到一个URI中
### 何时使用资源与工具
| 需求 | 使用 |
|------|-----|
| 应用需要显示文件选择器 | 📚 **资源** |
| Claude需要 *计算* 某些内容 | 🛠️ **工具** |
| 数据进入UI列表,而不是自动进入提示 | 📚 **资源** |
| LLM应决定何时/获取什么 | 🛠️ **工具** |
---
## 📖 访问资源
### 客户端:`read_resource()`
```python
import json
from pydantic import AnyUrl
async def read_resource(self, uri: str) -> str | dict:
"""从连接的MCP服务器读取资源。"""
result = await self.session.read_resource(AnyUrl(uri))
resource = result.contents[0] # 内容列表中的第一个项目
# 根据MIME类型解析
if resource.mime_type == "application/json":
return json.loads(resource.text)
return resource.text
```
### 响应解析逻辑
```python
# ... (其他代码保持不变)
```
---
## 📖 提示
> **提示** 是预先编写、测试良好的指令,作为斜杠命令。
### 客户端提示
```python
# ... (其他代码保持不变)
```
---
## 📑 快速参考
### 装饰器和SDK调用
| 装饰器/方法 | 描述 |
|--------------|-------------|
| `@mcp.tool` | 标记函数为工具 |
| `@mcp.resource` | 标记函数为资源 |
| `list_tools()` | 获取服务器提供的工具列表 |
| `call_tool()` | 在服务器上执行工具 |
| `read_resource()` | 从服务器读取资源 |
| `list_prompts()` | 获取服务器提供的提示列表 |
| `get_prompt()` | 获取服务器上的提示 |
### 提示和工具
| 提示/工具 | 描述 |
|--------------|-------------|
| `/help` | 显示帮助信息 |
| `/list_tools` | 列出所有工具 |
| `/call_tool <tool_name>` | 调用工具 |
| `/list_resources` | 列出所有资源 |
| `/read_resource <resource_uri>` | 读取资源 |
### 故障排除
| 错误 | 解决方案 |
|--------------|-------------|
| 连接超时 | 检查网络连接 |
| 工具调用失败 | 检查工具定义 |
| 资源读取失败 | 检查资源URI |
### 附加说明
* 请参阅 [MCP 官方文档](https://modelcontextprotocol.io) 以获取更多信息。
* 请参阅 [Anthropic 认证课程](https://anthropic.com) 以获取更多信息。
---
## 附录
### 词汇表
* **MCP**:模型上下文协议
* **工具**:一种由Claude调用的函数
* **资源**:一种由应用程序控制的原始数据
* **提示**:一种预先编写、测试良好的指令
### 变更日志
* **v1.0.0**:初始版本
### 致谢
* 感谢 [Anthropic](https://anthropic.com) 提供了MCP认证课程。
* 感谢 [MCP 社区](https://modelcontextprotocol.io/community) 提供的反馈和支持。
# 在客户端
async def get_doc_list(self) -> list[str]:
docs = await self.read_resource("docs://documents")
# 返回: ["report.pdf", "launch.md", "design.txt"]
return docs
async def get_doc(self, doc_id: str) -> str:
text = await self.read_resource(f"documents/{doc_id}")
# 返回: "Q4 revenue was up 23%..."
return text
### 如何在 CLI 中集成
```python
# 在聊天机器人中
async def pick_document():
docs = await client.get_doc_list() # 读取资源
selected = pick_with_arrows(docs) # UI 级别的选择器
contents = await client.get_doc(selected) # 读取另一个资源
return contents # 注入到 LLM 提示中
```
### 为什么这样做很重要
- 📚 文档选择在 LLM 调用之前进行
- ✅ 选择的文档内容会自动包含在提示中
- 🚫 在聊天时不需要 `read_doc` 工具 — 该操作在 UI 层完成
- 🔌 `json` 和 `pydantic.AnyUrl` 是唯一需要的额外依赖
---
## 💬 提示
> **提示** 是用户控制的原生功能。**用户** 触发它们(斜杠命令、按钮等)。
### 思维模型
```
提示 = 预先编写、测试过的指令,由服务器作者编写
(例如 "/format"、"/summarize"、"/translate")
→ 为用户服务
```
### 为什么提示存在
没有提示,用户每次都需要编写自己的指令。MCP 让 **服务器作者** 封装领域专业知识:
> "我对这个服务非常了解 — 这里有一个针对最常见工作流的经过测试的提示模板。只需公开它。"
### 实现模式
```python
from mcp.server.fastmcp.prompts import base
@mcp.prompt(
name="format",
description="将给定的文档重写为干净的 Markdown。"
)
def format_document(doc_id: str) -> list:
"""为 Claude 返回对话消息。"""
prompt_text = f"""
请将文档 "{doc_id}" 的内容重写为干净的 Markdown。
步骤:
1. 使用 read_doc_contents 工具读取文档。
2. 重新组织标题、列表和代码块。
3. 使用 edit_document 工具将结果保存回去。
"""
return [base.user_message(prompt_text)]
```
### 工作流程
```mermaid
sequenceDiagram
participant U as 👤 用户
participant CLI as 💻 聊天 CLI
participant C as 🔌 MCP 客户端
participant S as ⚙️ MCP 服务器
participant L as 🤖 Claude
U->>CLI: /format
CLI->>U: 选择文档(方向键)
U->>CLI: 选择 report.pdf
CLI->>C: get_prompt("format", {doc_id: "report.pdf"})
C->>S: get_prompt 请求
S-->>C: 消息(带有 doc_id 插值)
C-->>CLI: 消息
CLI->>L: 消息
L->>L: 调用 read_doc_contents,然后 edit_document
L-->>CLI: 重新格式化文档
CLI->>U: ✅ 完成
```
### 提示定义的剖析
```
@mcp.prompt 装饰器
↓
名称 + 描述 ← 表现为斜杠命令
↓
带有参数的函数 ← 参数成为斜杠命令参数
↓
返回 list[messages] ← Claude 的直接对话输入
```
### 现实示例
- 💬 Claude UI 中的聊天启动按钮 → **提示**
- 📁 "选择 Google Drive 文件" 自动补全 → **资源**
- ⚙️ "运行此 JavaScript 代码片段" → **工具**
---
## 🎯 客户端提示
### 实现的两种方法
```python
async def list_prompts(self) -> list:
"""获取服务器公开的每个提示。"""
result = await self.session.list_prompts()
return result.prompts # 或 result.props,取决于 SDK 版本
async def get_prompt(self, name: str, arguments: dict) -> list:
"""获取具有已填充参数的特定提示。"""
result = await self.session.get_prompt(name, arguments)
return result.messages
```
### 参数流程
```
用户输入: /format report.pdf
↓
客户端接收: name="format",arguments={"doc_id": "report.pdf"}
↓
提示函数: format_document(doc_id: str) ← 关键字参数注入
↓
插值: "请重写文档 'report.pdf' 的内容..."
↓
返回: Claude 对话消息列表
```
### CLI 集成
```python
async def handle_slash_command(cmd: str, arg: str):
if cmd == "format":
prompts = await client.list_prompts()
# prompts[0] 是 "format" 提示
messages = await client.get_prompt(
"format",
{"doc_id": arg}
)
# 将消息发送到 Claude
response = await claude.messages.create(
model="claude-sonnet-4-5",
messages=messages,
tools=await client.list_tools(), # 以便它可以读取/编辑文档
)
print(response.content)
```
### 核心概念
> **提示是服务器定义的模板。** 客户端通过名称和参数调用它们;服务器插值并返回准备发送的消息。
---
## 🧠 MCP 审查
三个 MCP 原始功能服务于 **三个不同的控制循环**。通过询问 *"谁触发它?"* 来选择正确的一个。
### 决策框架
```mermaid
flowchart TD
Start([我需要什么?]) --> Q1{谁决定<br/>何时运行?}
Q1 -->|🤖 Claude| Tools[🛠️ 构建工具]
Q1 -->|🖥️ 应用代码| Resources[📚 公开资源]
Q1 -->|👤 用户| Prompts[💬 定义提示]
Tools --> T[为模型添加功能<br/>例如 JS 执行、DB 查询]
Resources --> R[将数据引入应用<br/>用于 UI 或提示增强<br/>例如文件列表、自动补全]
Prompts --> P[为高级用户提供预定义工作流<br/>例如 /format、/summarize]
style Tools fill:#7C3AED,color:#fff
style Resources fill:#0EA5E9,color:#fff
style Prompts fill:#EC4899,color:#fff
```
### 侧边比较
| 方面 | 🛠️ 工具 | 📚 资源 | 💬 提示 |
|--------|----------|--------------|-----------|
| **控制者** | 模型(Claude) | 应用代码 | 用户(斜杠命令、按钮) |
| **主要目的** | 给 Claude *新功能* | 将 *数据* 引入应用 | 触发 *预定义工作流* |
| **触发器** | Claude 的推理决定 | 您的代码调用 `read_resource` | 用户输入 `/command` |
| **服务器装饰器** | `@mcp.tool()` | `@mcp.resource()` | `@mcp.prompt()` |
| **客户端 SDK 调用** | `list_tools()` / `call_tool()` | `list_resources()` / `read_resource()` | `list_prompts()` / `get_prompt()` |
| **返回** | 计算结果 | 数据(JSON 或文本) | 对话消息 |
| **服务对象** | **模型** | **应用** | **用户** |
| **现实示例** | 用于数学的 JavaScript 执行 | Google Drive 文档列表 | Claude 的聊天启动按钮 |
| **生命周期** | 短暂 — 按需触发 | 在应用请求时拉取 | 由用户操作触发 |
### 经验法则
```
需要 Claude 执行操作? → 🛠️ 工具
需要应用显示数据? → 📚 资源
需要工作流快捷方式? → 💬 提示
```
### 记忆技巧
> **T.A.P.** — **T**ools 服务模型,**A**pp 拉取资源,**P**rompts 服务用户。
---
## ⚡ 快速参考
### 服务器端装饰器
```python
# ── 工具 ───────────────────────────────────────────
@mcp.tool(name="...", description="...")
def my_tool(arg: str = Field(description="...")) -> str:
return ...
# ── 资源(静态) ─────────────────────────────
@mcp.resource(uri="docs://list", mime_type="application/json")
def list_items() -> list[str]:
return [...]
# ── 资源(模板) ──────────────────────────
@mcp.resource(uri="docs://{doc_id}", mime_type="text/plain")
def fetch_item(doc_id: str) -> str:
return ...
# ── 提示 ────────────────────────────────────────
@mcp.prompt(name="format", description="...")
def my_prompt(doc_id: str) -> list:
return [base.user_message("...")]
```
### 客户端 SDK 调用
```python
# ── 工具 ─────────────────────────────────────────
tools = await session.list_tools()
result = await session.call_tool(name, arguments)
# ── 资源 ─────────────────────────────────────
all_res = await session.list_resources()
data = await session.read_resource(AnyUrl("docs://x"))
# ── 提示 ───────────────────────────────────────
all_p = await session.list_prompts()
msgs = await session.get_prompt(name, arguments)
```
### 项目备忘录
| 任务 | 命令 |
|------|---------|
| 安装依赖 | `uv sync` |
| 运行聊天机器人 | `uv run main.py` |
| 在浏览器中调试服务器 | `mcp dev mcp_server.py` |
| 快速数学健全性检查 | `"what's one plus one"` |
### 常见陷阱
- ❌ 忘记在 `connect()` 后调用 `await session.initialize()`
- ❌ 未清理会话 → 文件描述符泄漏
- ❌ 将 `read_resource` 结果视为 JSON 时已解析
- ❌ 在需要资源(或反之亦然)时构建工具 — 重新检查控制循环
---
## 📚 资源和进一步阅读
- 📘 [MCP 官方规范](https://modelcontextprotocol.io)
- 🐍 [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- 🎓 [Anthropic Academy](https://anthropic.com) — 原始认证课程
- 🧪 [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — 调试 UI
---
## 📝 许可证
这些是 Anthropic 的 MCP 认证课程衍生的个人学习笔记。在 **MIT License** 下共享 — 免费使用,感谢 attribution。
---
<div align="center">
**⭐ 如果这帮助您理解 MCP,请在仓库上点个星星! ⭐**
用 🧠 + ☕ 学习 Model Context Protocol 时制作
</div>
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器