Agent工坊

【Agent工坊】30分钟搭建你的第一个MCP Server:让AI Agent真正干活

你的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_postgressearch_elastic PostgreSQL、ES
文件操作 read_filewrite_filelist_dir 本地文件系统
浏览器控制 navigateclickscreenshot Playwright
API 调用 send_slackcreate_issue Slack、GitHub
代码执行 run_pythonrun_sql Python/SQL 沙箱
搜索 search_websearch_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 从「聊天机器人」升级为「数字员工」的关键一步。今天你学会了:

  1. 5 分钟搭建 Python 环境
  2. 15 分钟编写 3 个工具的 MCP Server
  3. 10 分钟接入 Hermes Agent / Claude Code / Claude Desktop
  4. 10 分钟替换为真实 API

下一步:把你最常用的 3 个内部工具(查数据、发通知、操作文件)封装成 MCP Server。你会发现——AI Agent 真的开始「干活」了。


AI创业 #MCP #Agent工坊 #HermesAgent #ClaudeCode #一人公司