MCP协议超详细教程,从入门到实战
身份:AI工具探索者 | 写作日期:2026年5月10日
一、场景:为什么我需要MCP?
上周我遇到了一个很尴尬的场景。
我想让Claude帮我分析本地项目的依赖关系,然后自动生成一份升级建议。我打开Claude Desktop,问它"帮我看看这个项目的package.json有什么可以升级的"。
它给了我一堆建议。但问题是------它根本看不到我本地文件!我只能手动把package.json复制粘贴给它,它再给我建议,我再手动改代码。来回折腾了十几分钟,最后发现它连node_modules里的版本冲突都没看出来。
那一刻我突然意识到:AI模型再聪明,也只是一个"文本处理器"。它看不到你的文件,连不到你的数据库,更没法帮你执行命令。
直到我发现了MCP。
二、MCP到底是什么?
MCP(Model Context Protocol)是Anthropic在2024年底推出的一个开源协议。
用一句话概括:MCP就是AI应用的"USB-C接口"。
就像USB-C让你能用一根线连接各种设备一样,MCP让你能用一个标准方式,让AI模型连接到:
- 本地文件(比如你的项目代码)
- 数据库(PostgreSQL、MySQL、SQLite)
- 外部工具(搜索引擎、计算器、日历)
- 自定义工作流(你写的一堆Python脚本)
核心思想就一个:别让每个AI应用都单独写一套集成代码。写一个MCP服务器,所有支持MCP的AI客户端都能用。
三、环境准备
需要的东西
| 项目 | 版本 | 说明 |
|---|---|---|
| Python | 3.10+ | 我用的是3.12 |
| uv | 最新版 | 包管理器,比pip快很多 |
| Claude Desktop | 最新版 | 或者Cursor、VS Code Copilot |
安装MCP SDK
bash
# 用uv创建项目
uv init mcp-tutorial
cd mcp-tutorial
uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 安装MCP SDK(带CLI工具)
uv add "mcp[cli]" httpx
踩坑1 :直接用
pip install mcp会装到旧版本,一定要用mcp[cli]这个extra,不然没有mcp命令行工具,调试会很麻烦。
四、动手:写一个任务追踪MCP服务器
我写了一个简单的任务追踪服务器,让Claude能帮我管理本地任务清单。
4.1 项目结构
bash
mcp-tutorial/
├── tasks.json # 任务数据文件
├── server.py # MCP服务器代码
└── pyproject.toml # 项目配置
4.2 任务数据文件(tasks.json)
json
{
"tasks": [
{
"id": 1,
"title": "学习MCP协议",
"status": "completed",
"priority": "high",
"created_at": "2026-05-08"
},
{
"id": 2,
"title": "写这篇教程",
"status": "in_progress",
"priority": "high",
"created_at": "2026-05-10"
},
{
"id": 3,
"title": "部署服务器到生产环境",
"status": "pending",
"priority": "medium",
"created_at": "2026-05-11"
}
]
}
4.3 核心代码(server.py)
python
"""
一个简单的任务追踪MCP服务器
让Claude能帮我管理本地任务清单
"""
import json
from pathlib import Path
from typing import Any
from mcp.server.fastmcp import FastMCP
# 初始化FastMCP服务器
# 名字会显示在Claude Desktop的MCP服务器列表里
mcp = FastMCP("TaskTracker")
# 数据文件路径
TASKS_FILE = Path(__file__).parent / "tasks.json"
def load_tasks() -> dict:
"""加载任务数据"""
if not TASKS_FILE.exists():
return {"tasks": []}
with open(TASKS_FILE, "r", encoding="utf-8") as f:
return json.load(f)
def save_tasks(data: dict) -> None:
"""保存任务数据"""
with open(TASKS_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# ==================== 工具(Tools) ====================
# 工具是AI可以主动调用的函数,AI决定什么时候用
@mcp.tool()
def add_task(title: str, priority: str = "medium") -> str:
"""添加一个新任务"""
data = load_tasks()
new_id = max((t["id"] for t in data["tasks"]), default=0) + 1
task = {
"id": new_id,
"title": title,
"status": "pending",
"priority": priority,
"created_at": "2026-05-10"
}
data["tasks"].append(task)
save_tasks(data)
return f"✅ 已添加任务 #{new_id}: {title}"
@mcp.tool()
def list_tasks(status: str | None = None) -> str:
"""列出所有任务,可选按状态过滤"""
data = load_tasks()
tasks = data["tasks"]
if status:
tasks = [t for t in tasks if t["status"] == status]
if not tasks:
return "📭 没有找到任务"
lines = ["📋 任务列表:"]
for t in tasks:
icon = {"pending": "⏳", "in_progress": "🔄", "completed": "✅"}.get(t["status"], "❓")
lines.append(f" {icon} #{t['id']} [{t['priority']}] {t['title']}")
return "\n".join(lines)
@mcp.tool()
def complete_task(task_id: int) -> str:
"""标记任务为已完成"""
data = load_tasks()
for task in data["tasks"]:
if task["id"] == task_id:
task["status"] = "completed"
save_tasks(data)
return f"✅ 任务 #{task_id} 已完成!"
return f"❌ 没找到任务 #{task_id}"
@mcp.tool()
def delete_task(task_id: int) -> str:
"""删除一个任务"""
data = load_tasks()
original_count = len(data["tasks"])
data["tasks"] = [t for t in data["tasks"] if t["id"] != task_id]
if len(data["tasks"]) == original_count:
return f"❌ 没找到任务 #{task_id}"
save_tasks(data)
return f"🗑️ 已删除任务 #{task_id}"
# ==================== 资源(Resources) ====================
# 资源是只读数据源,AI可以读取但不能修改
@mcp.resource("tasks://all")
def get_all_tasks() -> str:
"""获取所有任务的原始JSON数据"""
data = load_tasks()
return json.dumps(data, ensure_ascii=False, indent=2)
@mcp.resource("tasks://pending")
def get_pending_tasks() -> str:
"""获取待办任务"""
data = load_tasks()
pending = [t for t in data["tasks"] if t["status"] == "pending"]
return json.dumps(pending, ensure_ascii=False, indent=2)
# ==================== 提示(Prompts) ====================
# 提示是预定义的指令模板,用户手动触发
@mcp.prompt()
def daily_planner() -> str:
"""每日计划助手"""
return """请帮我规划今天的工作:
1. 先列出所有待办任务(pending状态)
2. 根据优先级排序
3. 帮我制定一个合理的时间安排
如果任务太多,建议我优先做哪些。"""
# ==================== 启动服务器 ====================
def main():
# 重要:STDIO传输模式下,日志必须写到stderr,不能写stdout
# 写stdout会破坏JSON-RPC协议通信
import sys
print("🚀 TaskTracker MCP服务器已启动", file=sys.stderr)
print(" 连接方式: stdio", file=sys.stderr)
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
五、连接Claude Desktop
5.1 配置Claude Desktop
打开Claude Desktop的配置文件(路径因系统而异):
| 系统 | 路径 |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
添加MCP服务器配置:
json
{
"mcpServers": {
"task-tracker": {
"command": "uv",
"args": [
"--directory",
"/Users/yourname/mcp-tutorial",
"run",
"server.py"
]
}
}
}
踩坑2:路径一定要用绝对路径!我用相对路径试了三次都连不上,最后才发现是这个问题。
5.2 重启Claude Desktop
保存配置后,必须完全关闭再打开Claude Desktop。不是最小化,是彻底退出。
打开后,在Claude的输入框旁边会看到一个插头图标🔌,点击就能看到已连接的MCP服务器。
六、效果演示
连接成功后,你可以这样跟Claude对话:
用户:帮我看看今天有哪些任务要做
Claude (调用list_tasks工具):
less
📋 任务列表:
⏳ #3 [medium] 部署服务器到生产环境
用户:把任务3标记为已完成
Claude (调用complete_task工具):
bash
✅ 任务 #3 已完成!
用户:添加一个新任务"学习MCP资源API",优先级高
Claude (调用add_task工具):
bash
✅ 已添加任务 #4: 学习MCP资源API
用户:显示所有待办任务
Claude (读取tasks://pending资源):
json
[
{
"id": 4,
"title": "学习MCP资源API",
"status": "pending",
"priority": "high",
"created_at": "2026-05-10"
}
]
七、常见问题FAQ
Q1: 为什么我的Claude Desktop看不到MCP服务器?
A: 三个最常见原因:
- 配置文件路径不对(检查是不是写到了正确的
claude_desktop_config.json) - 路径用了相对路径(必须用绝对路径)
- 没重启Claude Desktop(保存后必须完全退出再打开)
Q2: 日志看不到,怎么调试?
A : MCP服务器用STDIO传输时,stdout被协议占用了。所有日志必须写stderr:
python
# ❌ 错误
print("Debug info")
# ✅ 正确
import sys
print("Debug info", file=sys.stderr)
# 或者用logging
import logging
logging.info("Debug info")
Q3: 能用Python以外的语言写MCP服务器吗?
A: 当然可以!官方支持:
- TypeScript/JavaScript :
@modelcontextprotocol/sdk - Python :
mcpSDK(本文用的) - Rust 、Go 、Java也有官方SDK
Q4: MCP服务器一定要本地运行吗?
A : 不一定。除了stdio(本地进程),还支持:
- SSE(Server-Sent Events):HTTP长连接,适合远程服务器
- WebSocket:双向通信
但新手建议先用stdio,最简单。
八、总结
MCP的核心就三件事:
| 概念 | 谁控制 | 作用 |
|---|---|---|
| Tools | AI模型 | AI主动调用的函数(写文件、调API) |
| Resources | AI应用 | 只读数据源(文件、数据库) |
| Prompts | 用户 | 预定义的工作流模板 |
写一个MCP服务器,所有支持MCP的AI客户端都能用------这就是它的价值。
我现在已经用它连接了:
- 本地项目文件(让Claude能直接读代码)
- SQLite数据库(让Claude能查数据)
- 自定义Python脚本(让Claude能执行我写的工具)
说实话,刚开始觉得有点复杂,但写通一个服务器后,后面都是复制粘贴改改而已。
如果你也想让AI真正"动手"做事而不是光动嘴,MCP值得试试。
如果觉得有帮助,欢迎点赞收藏 ❤️ 更多AI工具实战教程,关注我第一时间获取~