你的AI Agent现在只会聊天?给它接上MCP Server,它就能查数据库、发邮件、操控浏览器——而且只需80行Python代码。
为什么你需要MCP Server
如果你正在用 Hermes Agent、Claude Code 或任何支持 MCP 的 AI Agent,你可能会遇到一个核心痛点:Agent 很聪明,但它碰不到你的数据。
它不能查你的数据库,不能读你的文件系统,不能调用你的内部API。它像是一个被困在聊天框里的超级大脑——有智商,没手脚。
MCP(Model Context Protocol)就是给这个大脑装上手和脚。
MCP 是 Anthropic 于 2024 年底发布的开源协议,已经被 Hermes Agent、Claude Code、Cursor、Windsurf 等主流 AI 工具广泛采用。它的核心思路极其简单:
AI Agent ←→ MCP Protocol ←→ MCP Server ←→ 你的工具/数据
MCP Server 是一个轻量级服务,暴露一组「工具」(Tools)给 AI Agent 调用。Agent 看到工具列表后,就可以像调用函数一样使用它们。
这篇教程的目标:30分钟内,从零搭建一个可运行的 MCP Server,让 Hermes Agent 或 Claude Code 能通过它查询天气、操作文件、调用任何 Python 函数。
环境准备(5分钟)
只需要 Python 3.10+,不需要 Docker、不需要数据库。
# 创建项目目录
mkdir my-first-mcp && cd my-first-mcp
# 创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate
# 安装 MCP SDK
pip install mcp
验证安装:
python3 -c "import mcp; print(mcp.__version__)"
# 输出: 1.x.x
编写第一个 MCP Server(15分钟)
我们从一个「天气查询」工具开始。完整代码 80 行,逐段拆解:
1. 启动文件:server.py
#!/usr/bin/env python3
"""
my-first-mcp/server.py
一个最小化的 MCP Server,暴露 3 个工具:
- get_weather:查询天气(模拟)
- read_file:读取本地文件
- run_python:安全执行 Python 表达式
"""
import asyncio
import json
import os
from pathlib import Path
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationCapabilities
from mcp.server.stdio import stdio_server
# ============================================================
# 第一步:创建 Server 实例
# ============================================================
server = Server("my-first-mcp")
# ============================================================
# 第二步:注册工具
# ============================================================
@server.list_tools()
async def handle_list_tools() -> list:
"""当 Agent 询问「你能做什么」时,返回工具列表"""
return [
{
"name": "get_weather",
"description": "查询指定城市的天气(模拟数据)",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如 'Beijing' 或 'Shanghai'"
}
},
"required": ["city"]
}
},
{
"name": "read_local_file",
"description": "读取本地文件内容(仅限 /tmp 目录)",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "文件路径,必须以 /tmp/ 开头"
}
},
"required": ["path"]
}
},
{
"name": "run_python_expr",
"description": "安全执行一个简单的 Python 数学表达式",
"inputSchema": {
"type": "object",
"properties": {
"expr": {
"type": "string",
"description": "Python 数学表达式,如 '2**10 + 3*5'"
}
},
"required": ["expr"]
}
}
]
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict) -> list:
"""当 Agent 调用工具时,执行实际逻辑"""
if name == "get_weather":
city = arguments.get("city", "Beijing")
# 模拟天气数据(实际项目中可接入真实 API)
weather_data = {
"Beijing": {"temp": 22, "humidity": 45, "condition": "晴"},
"Shanghai": {"temp": 26, "humidity": 70, "condition": "多云"},
"Shenzhen": {"temp": 30, "humidity": 80, "condition": "阵雨"},
}
data = weather_data.get(city, {"temp": 20, "humidity": 50, "condition": "未知"})
return [{
"type": "text",
"text": f"🌤️ {city}:温度 {data['temp']}°C,湿度 {data['humidity']}%,天气 {data['condition']}"
}]
elif name == "read_local_file":
path = arguments.get("path", "")
# 安全检查:只允许读取 /tmp 目录
if not path.startswith("/tmp/"):
return [{"type": "text", "text": "❌ 安全限制:只能读取 /tmp/ 目录下的文件"}]
try:
content = Path(path).read_text(encoding="utf-8")
return [{"type": "text", "text": f"📄 {path}:\n{content[:2000]}"}]
except FileNotFoundError:
return [{"type": "text", "text": f"❌ 文件不存在: {path}"}]
elif name == "run_python_expr":
expr = arguments.get("expr", "")
# 安全限制:白名单允许的字符
allowed = set("0123456789+-*/()., absintfloatroundminmaxsumlen ")
if not all(c in allowed for c in expr):
return [{"type": "text", "text": "❌ 安全限制:表达式包含不允许的字符"}]
try:
result = eval(expr, {"__builtins__": {}}, {})
return [{"type": "text", "text": f"🧮 {expr} = {result}"}]
except Exception as e:
return [{"type": "text", "text": f"❌ 计算错误: {e}"}]
# ============================================================
# 第三步:启动 Server(stdio 传输)
# ============================================================
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationCapabilities(
sampling=None,
experimental=None,
roots=None
),
notification_options=NotificationOptions(
tools_changed=False
)
)
if __name__ == "__main__":
asyncio.run(main())
2. 本地测试
MCP Inspector 是官方提供的调试工具:
# 安装 Inspector
npx @anthropic-ai/mcp-inspector python3 server.py
浏览器打开 http://localhost:5173,你会看到 3 个工具。点击 get_weather,输入 {"city": "Shanghai"},点击 Run——返回天气数据。
这就是一个完整可用的 MCP Server。 它已经可以被任何 MCP 客户端调用了。
接入 Hermes Agent/Claude Code(10分钟)
方案 A:接入 Hermes Agent
Hermes Agent 通过配置文件接入 MCP Server:
// ~/.hermes/config.json 中添加
{
"mcp_servers": {
"my-first-mcp": {
"command": "python3",
"args": ["/path/to/my-first-mcp/server.py"],
"env": {}
}
}
}
重启 Hermes Agent,在对话中输入:
查一下北京的天气,然后把深圳的天气也查一下,对比两地的温差。
Hermes Agent 会自动识别需要调用 get_weather 工具,分两次查询后给出对比分析。
方案 B:接入 Claude Code
Claude Code 使用 .mcp.json 配置文件:
// 项目根目录或 ~/.claude/.mcp.json
{
"mcpServers": {
"my-first-mcp": {
"command": "python3",
"args": ["/path/to/my-first-mcp/server.py"]
}
}
}
在 Claude Code 对话中直接说:
用 get_weather 查一下上海天气,然后用 run_python_expr 算一下
把温度从摄氏度转成华氏度。
方案 C:接入 Claude Desktop
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// 或 %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"my-first-mcp": {
"command": "python3",
"args": ["/path/to/my-first-mcp/server.py"]
}
}
}
进阶:接入真实API(额外10分钟)
把天气查询换成真实 API,只需修改 handle_call_tool 中的 get_weather 分支:
elif name == "get_weather":
city = arguments.get("city", "Beijing")
import urllib.request
# 使用免费天气 API(无需注册)
url = f"https://wttr.in/{city}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "MCP-Server"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
current = data["current_condition"][0]
return [{
"type": "text",
"text": (
f"🌤️ {city}:温度 {current['temp_C']}°C,"
f"湿度 {current['humidity']}%,"
f"天气 {current['weatherDesc'][0]['value']},"
f"风速 {current['windspeedKmph']}km/h"
)
}]
只需改 10 行代码,你的 MCP Server 就从「模拟数据」升级到了「实时数据」。
MCP Server 能做的远不止这些
我们的示例只有 3 个工具,但 MCP 协议支持的工具类型几乎无限:
| 用途 | 示例工具 | 数据源 |
|---|---|---|
| 数据库查询 | query_postgres、search_elastic |
PostgreSQL、ES |
| 文件操作 | read_file、write_file、list_dir |
本地文件系统 |
| 浏览器控制 | navigate、click、screenshot |
Playwright |
| API 调用 | send_slack、create_issue |
Slack、GitHub |
| 代码执行 | run_python、run_sql |
Python/SQL 沙箱 |
| 搜索 | search_web、search_docs |
Tavily、内部知识库 |
一个 MCP Server 可以包含任意多个工具。你甚至可以写一个「超级 Server」,把团队所有内部工具打包成一个 MCP 端点。
生产环境的三个关键提示
1. 安全沙箱是必须的
run_python_expr 中的 eval() 是演示用途。生产环境必须使用沙箱(Docker、gVisor、或 restricted Python):
# 生产级安全方案:使用 RestrictedPython 或 subprocess 隔离
import subprocess
result = subprocess.run(
["python3", "-c", expr],
capture_output=True, text=True, timeout=5
)
2. 工具描述决定 Agent 的使用质量
Agent 是通过工具描述来理解工具用途的。如果你的描述是「执行操作」,Agent 不会用。但如果你写「查询 PostgreSQL 数据库中的用户表,支持按注册日期范围过滤」,Agent 就会精准调用。
工具描述 = Agent 的「使用说明书」。写得越具体,Agent 用得越好。
3. 错误处理要返回可读信息
Agent 看到错误后会自动重试或调整策略。如果只返回 Error: 500,它会陷入死循环。正确做法:
return [{"type": "text", "text": f"❌ 数据库连接失败。({e})。请检查 VPN 是否开启。"}]
总结
MCP Server 是 AI Agent 从「聊天机器人」升级为「数字员工」的关键一步。今天你学会了:
- 5 分钟搭建 Python 环境
- 15 分钟编写 3 个工具的 MCP Server
- 10 分钟接入 Hermes Agent / Claude Code / Claude Desktop
- 10 分钟替换为真实 API
下一步:把你最常用的 3 个内部工具(查数据、发通知、操作文件)封装成 MCP Server。你会发现——AI Agent 真的开始「干活」了。
