从零开始用 MCP:让 AI 助手连接你的数据和工具的完整实战指南
本文定位:面向开发者的 MCP(Model Context Protocol)入门教程,教你如何让 Claude、Cursor 等 AI 助手连接外部数据源和工具,打造真正的智能工作流。
什么是 MCP?为什么它如此重要?
MCP(Model Context Protocol,模型上下文协议)是一个开源标准,用于连接 AI 应用程序与外部系统。
想象一下:你的 AI 助手可以访问你的 Google 日历和 Notion 数据库,成为真正个性化的助理;Claude Code 可以直接读取 Figma 设计稿生成完整 Web 应用;企业聊天机器人可以连接组织内多个数据库,让用户通过对话分析数据。
MCP 就像 AI 应用的 USB-C 接口——正如 USB-C 提供了连接电子设备的标准化方式,MCP 提供了连接 AI 应用与外部系统的标准化协议。
MCP 能实现什么?
- 个人助理场景:AI 读取你的日历、邮件、笔记,提供个性化建议
- 开发场景:AI 直接访问代码库、数据库、API 文档,辅助编程
- 企业场景:AI 连接 CRM、ERP、数据库系统,自动化业务流程
- 创意场景:AI 控制 Blender 创建 3D 设计,驱动 3D 打印机输出实物
为什么开发者应该关注 MCP?
| 角色 | MCP 带来的价值 |
|---|---|
| 开发者 | 减少开发时间和复杂度,构建一次即可集成到多个 AI 应用 |
| AI 应用 | 接入丰富的数据源、工具和应用生态系统 |
| 终端用户 | 获得更强大的 AI 能力,让 AI 访问你的数据并代表你执行任务 |
MCP 的核心概念
在开始构建之前,我们需要理解 MCP 的三个核心能力:
1. Resources(资源)
资源是类文件的数据,可以被客户端读取。例如:
- API 响应数据
- 本地文件内容
- 数据库查询结果
- 网页内容
资源让 AI 能够”读取”外部数据,就像读取本地文件一样自然。
2. Tools(工具)
工具是可以被 LLM 调用的函数(需要用户批准)。例如:
- 发送电子邮件
- 创建数据库记录
- 调用外部 API
- 执行系统命令
工具让 AI 能够”执行操作”,而不仅仅是回答问题。
3. Prompts(提示模板)
提示模板是预定义的指令,帮助用户完成特定任务。例如:
- 代码审查提示
- 文档生成提示
- 数据分析提示
提示模板让 AI 的行为更加一致和可预测。
实战:构建你的第一个 MCP 服务器
本教程将带你构建一个天气查询 MCP 服务器,让 AI 能够获取实时天气数据和预警信息。
环境准备
系统要求:
- Python 3.10 或更高版本
- MCP Python SDK 1.2.0 或更高版本
第一步:安装 uv(推荐的 Python 包管理器)
# macOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
安装完成后重启终端,确保 uv 命令可用。
第二步:创建项目
# 创建项目目录 uv init weather cd weather # 创建虚拟环境 uv venv source .venv/bin/activate # Windows: .venv\Scripts\activate # 安装依赖 uv add "mcp[cli]" httpx # 创建服务器文件 touch weather.py # Windows: new-item weather.py
编写 MCP 服务器代码
创建 weather.py 文件,添加以下代码:
from typing import Any
import sys
import logging
import httpx
from mcp.server.fastmcp import FastMCP
# 初始化 FastMCP 服务器
mcp = FastMCP("weather")
# 常量配置
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
async def make_nws_request(url: str) -> dict[str, Any] | None:
"""向 NWS API 发送请求,包含适当的错误处理。"""
headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception as e:
logging.error(f"Request failed: {e}")
return None
def format_alert(feature: dict) -> str:
"""将预警信息格式化为可读字符串。"""
props = feature["properties"]
return f"""
事件:{props.get("event", "未知")}
区域:{props.get("areaDesc", "未知")}
严重程度:{props.get("severity", "未知")}
描述:{props.get("description", "无可用描述")}
建议:{props.get("instruction", "无具体建议")}
"""
@mcp.tool()
async def get_alerts(state: str) -> str:
"""获取美国某州的天气预警。
Args:
state: 两位字母的美国州代码(如 CA, NY)
"""
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data or "features" not in data:
return "无法获取预警信息或未找到预警。"
if not data["features"]:
return "该州当前无活跃预警。"
alerts = [format_alert(feature) for feature in data["features"]]
return "\n---\n".join(alerts)
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""获取某地的天气预报。
Args:
latitude: 纬度
longitude: 经度
"""
# 首先获取预报网格端点
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return "无法获取该地点的预报数据。"
# 从 points 响应中获取预报 URL
forecast_url = points_data["properties"]["forecast"]
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "无法获取详细预报。"
# 格式化时段为可读预报
periods = forecast_data["properties"]["periods"]
forecasts = []
for period in periods[:5]: # 只显示未来 5 个时段
forecast = f"""
{period["name"]}:
温度:{period["temperature"]}°{period["temperatureUnit"]}
风力:{period["windSpeed"]} {period["windDirection"]}
预报:{period["detailedForecast"]}
"""
forecasts.append(forecast)
return "\n---\n".join(forecasts)
def main():
"""初始化并运行服务器。"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler(sys.stderr)]
)
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
⚠️ 重要:MCP 服务器的日志处理
对于基于 STDIO 的 MCP 服务器,永远不要向 stdout 写入内容(包括 print()),这会破坏 JSON-RPC 消息导致服务器崩溃。
正确做法:
# ❌ 错误(STDIO 服务器)
print("处理请求中")
# ✅ 正确(写入 stderr)
print("处理请求中", file=sys.stderr)
# ✅ 正确(使用 logging)
logging.info("处理请求中")
配置 Claude for Desktop 使用 MCP 服务器
第一步:安装 Claude for Desktop
前往 claude.ai/download 下载并安装最新版本的 Claude for Desktop。
第二步:编辑配置文件
打开 Claude for Desktop 的配置文件:
macOS/Linux:
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
Windows:
code $env:AppData\Claude\claude_desktop_config.json
如果文件不存在,请创建它。
第三步:添加 MCP 服务器配置
在配置文件中添加以下内容(记得替换为你的实际路径):
macOS/Linux:
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"/绝对/路径/to/weather",
"run",
"weather.py"
]
}
}
}
Windows:
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"C:\\绝对\\路径\\to\\weather",
"run",
"weather.py"
]
}
}
}
注意事项:
- 使用绝对路径(在终端运行
pwd或cd获取) - Windows 路径使用双反斜杠
\\或正斜杠/ - 可能需要指定
uv的完整路径(运行which uv或where uv获取)
第四步:重启 Claude for Desktop
保存配置文件后,完全退出并重新启动 Claude for Desktop。
测试你的 MCP 服务器
重启 Claude for Desktop 后,你应该能在界面中看到 MCP 相关的 UI 元素。
测试方法:
- 在对话框中输入:”查询加利福尼亚州的天气预警”
- 或:”获取纽约市(纬度 40.7128,经度 -74.0060)的天气预报”
Claude 会自动调用你配置的 MCP 服务器,获取实时天气数据并返回结果。
MCP 生态系统:现有服务器推荐
除了自己构建,你还可以使用社区已有的 MCP 服务器:
官方推荐服务器
| 服务器名称 | 功能 | 适用场景 |
|---|---|---|
| Filesystem | 访问本地文件系统 | 文件管理、代码浏览 |
| PostgreSQL | 连接 PostgreSQL 数据库 | 数据查询、分析 |
| SQLite | 连接 SQLite 数据库 | 本地数据管理 |
| Git | Git 仓库操作 | 版本控制、代码审查 |
| Puppeteer | 浏览器自动化 | 网页抓取、测试 |
| Slack | Slack 消息收发 | 团队沟通自动化 |
如何安装现有服务器
大多数 MCP 服务器可以通过配置文件快速添加:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
},
"git": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-git"]
}
}
}
进阶:构建生产级 MCP 服务器
1. 添加认证机制
对于访问敏感数据的服务器,添加认证是必要的:
import os
from functools import wraps
def require_auth(func):
@wraps(func)
async def wrapper(*args, **kwargs):
api_key = os.environ.get("WEATHER_API_KEY")
if not api_key:
raise PermissionError("API key not configured")
return await func(*args, **kwargs)
return wrapper
@mcp.tool()
@require_auth
async def get_premium_forecast(latitude: float, longitude: float) -> str:
"""获取高级天气预报(需要 API 密钥)。"""
# 实现...
2. 添加资源暴露
除了工具,还可以暴露资源供 AI 读取:
@mcp.resource("weather://current/{location}")
async def get_current_weather(location: str) -> str:
"""获取当前位置的实时天气。"""
# 实现...
return weather_data
3. 添加提示模板
创建预定义的提示模板帮助用户:
@mcp.prompt()
def weather_analysis_prompt(location: str, days: int = 7) -> str:
"""生成天气分析提示模板。"""
return f"""
请分析 {location} 未来 {days} 天的天气趋势,包括:
1. 温度变化趋势
2. 降水概率
3. 适合户外活动的日期建议
4. 需要关注的极端天气预警
"""
常见问题解答
Q1: MCP 服务器可以在生产环境使用吗?
可以,但需要注意:
- 添加适当的认证和授权机制
- 实现速率限制防止滥用
- 记录所有工具调用日志
- 对敏感数据进行脱敏处理
Q2: MCP 支持哪些 AI 客户端?
MCP 已被广泛支持,包括:
- Claude for Desktop(官方支持)
- Cursor(代码编辑器)
- Visual Studio Code(GitHub Copilot Chat)
- Windsurf(AI 原生 IDE)
- Continue.dev(开源 AI 编程助手)
- 以及更多社区客户端
Q3: 如何调试 MCP 服务器?
方法一:使用 MCP Inspector
npx @modelcontextprotocol/inspector uv run weather.py
方法二:查看日志
确保日志写入 stderr 或文件,然后检查日志输出。
方法三:使用测试客户端
编写简单的测试客户端验证服务器响应:
from mcp.client.stdio import stdio_client
import asyncio
async def test_server():
async with stdio_client(["uv", "run", "weather.py"]) as (read, write):
# 发送测试请求
await write.send_json({"jsonrpc": "2.0", "method": "tools/list", "id": 1})
response = await read.receive_json()
print(response)
asyncio.run(test_server())
Q4: MCP 的性能如何?
MCP 基于 JSON-RPC 2.0 协议,性能取决于:
- 传输方式:STDIO 最快(本地进程间通信),HTTP 次之,SSE 最慢
- 工具复杂度:简单工具响应在毫秒级,复杂操作可能需数秒
- 网络延迟:调用外部 API 时受网络影响
优化建议:
- 对于高频调用,使用缓存机制
- 对于耗时操作,实现异步处理
- 批量处理多个请求减少往返次数
总结与下一步
通过本教程,你已经:
- ✅ 理解了 MCP 的核心概念和架构
- ✅ 构建了第一个 MCP 天气服务器
- ✅ 配置了 Claude for Desktop 使用 MCP
- ✅ 学习了生产级服务器的最佳实践
下一步学习资源
- 官方文档:modelcontextprotocol.io
- GitHub 仓库:github.com/modelcontextprotocol
- 服务器示例:github.com/modelcontextprotocol/servers
- 客户端列表:modelcontextprotocol.io/clients
项目创意
尝试构建以下 MCP 服务器练手:
- Notion 连接器:让 AI 读写你的 Notion 页面
- GitHub 助手:自动创建 Issue、PR、审查代码
- 数据库查询工具:安全地查询生产数据库
- 邮件自动化:读取和发送 Gmail 邮件
- 日历管理:安排会议、提醒事项
参考资料: