MCP Server 开发实战

为什么要学 MCP?

说实话,最近半年 AI 开发圈最火的协议就是 MCP(Model Context Protocol)了。你可能已经用上了各种 AI 助手,但有没有想过:这些 AI 怎么连接你的数据库?怎么读你的本地文件?怎么调用你公司的内部 API?

答案就是 MCP。

你可以把它理解成 AI 世界的 USB-C 接口——以前每个 AI 应用对接外部系统都得写一套适配代码,现在有了统一协议,写一次就能到处用。Claude、ChatGPT、Cursor、VS Code Copilot 都已经支持了。

我之前也觉得这东西听着高大上,实际动手一搞,发现真没那么难。今天就把我的经验分享出来,带你从零搭一个能跑的 MCP Server。

MCP 架构示意图

先搞清楚 MCP 的架构

MCP 采用的是经典的 Client-Server 架构:

  • MCP Host:就是你的 AI 应用(比如 Claude Desktop、Cursor)
  • MCP Client:Host 里面负责跟 Server 通信的组件
  • MCP Server:暴露工具(Tools)、资源(Resources)、提示(Prompts)的服务端

通信方式有两种:

  • stdio:通过标准输入输出通信,适合本地工具
  • SSE(Server-Sent Events):通过 HTTP 通信,适合远程服务

今天我们重点搞 stdio 方式,因为上手最简单。

环境准备

Python 版本要求

# 需要 Python 3.10+
python --version
# Python 3.10.x 或更高

安装 MCP Python SDK

# 创建虚拟环境(推荐)
python -m venv mcp-env
source mcp-env/bin/activate  # Linux/Mac
# mcp-env\Scripts\activate   # Windows

# 安装 MCP SDK
pip install mcp

装完之后验证一下:

python -c "import mcp; print(mcp.__version__)"

没报错就 OK。

实战:写一个天气查询 MCP Server

我们来做一个实用的例子——让 AI 能查询城市天气。虽然是 mock 数据,但整个流程是完整的,你换成真实天气 API 就能用。

项目结构

weather-mcp-server/
├── server.py          # MCP Server 主文件
└── pyproject.toml     # 项目配置(可选)

核心代码

新建 server.py,写入以下内容:

import httpx
from mcp.server.fastmcp import FastMCP

# 创建 MCP Server 实例
mcp = FastMCP("weather-server")

# 模拟天气数据(实际项目中替换为真实 API)
WEATHER_DATA = {
    "北京": {"temp": 22, "condition": "晴", "humidity": 35, "wind": "北风3级"},
    "上海": {"temp": 25, "condition": "多云", "humidity": 65, "wind": "东风2级"},
    "广州": {"temp": 30, "condition": "阵雨", "humidity": 80, "wind": "南风2级"},
    "深圳": {"temp": 29, "condition": "阴", "humidity": 75, "wind": "西南风3级"},
    "成都": {"temp": 20, "condition": "小雨", "humidity": 70, "wind": "微风"},
    "杭州": {"temp": 24, "condition": "晴转多云", "humidity": 55, "wind": "东南风2级"},
}


@mcp.tool()
def get_weather(city: str) -> str:
    """查询指定城市的天气信息

    Args:
        city: 城市名称,如 北京、上海、广州
    """
    weather = WEATHER_DATA.get(city)
    if weather:
        return (
            f"📍 {city}天气\n"
            f"🌡️ 温度:{weather['temp']}°C\n"
            f"🌤️ 天气:{weather['condition']}\n"
            f"💧 湿度:{weather['humidity']}%\n"
            f"🌬️ 风力:{weather['wind']}"
        )
    return f"❌ 未找到城市「{city}」的天气数据,目前支持:{', '.join(WEATHER_DATA.keys())}"


@mcp.tool()
def list_cities() -> str:
    """列出所有可查询天气的城市"""
    cities = list(WEATHER_DATA.keys())
    return f"可查询的城市(共{len(cities)}个):{', '.join(cities)}"


@mcp.resource("weather://cities")
def get_cities_resource() -> str:
    """提供城市列表作为资源"""
    return "\n".join(WEATHER_DATA.keys())


if __name__ == "__main__":
    mcp.run()

就这么简单。我来逐行解释一下关键部分:

  1. FastMCP("weather-server"):创建 Server 实例,名字随便起
  2. @mcp.tool():装饰器把这个函数注册为一个 MCP 工具,AI 可以调用它
  3. 函数的 docstring:很重要!AI 靠这个理解工具的用途
  4. @mcp.resource():注册一个资源,AI 可以读取但不直接调用
  5. mcp.run():启动 Server,默认用 stdio 方式通信

运行测试

python server.py

启动后什么都不会输出——这是正常的,因为 stdio 模式下 Server 在等 Client 发消息。

配置 Claude Desktop 连接你的 Server

写好 Server 只是第一步,得让 AI 应用能发现它才行。

找到配置文件

不同系统配置文件位置不同:

# macOS
~/Library/Application Support/Claude/claude_desktop_config.json

# Windows
%APPDATA%\Claude\claude_desktop_config.json

# Linux(如果有 Claude Desktop)
~/.config/Claude/claude_desktop_config.json

添加 Server 配置

打开配置文件,加入你的 Server:

{
  "mcpServers": {
    "weather": {
      "command": "python",
      "args": ["/absolute/path/to/weather-mcp-server/server.py"]
    }
  }
}

注意:路径必须是绝对路径!写相对路径会找不到。

重启 Claude Desktop

保存配置后,重启 Claude Desktop。你会在工具栏看到一个小锤子图标 🔨,点开就能看到你注册的工具。

然后直接问 Claude:「北京今天天气怎么样?」它就会调用你的 get_weather 工具返回结果。

进阶:用 uv 管理依赖(推荐)

实际项目中,推荐用 uv 来管理 Python 环境和依赖,比 pip 好用太多:

# 安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# 初始化项目
uv init weather-mcp-server
cd weather-mcp-server

# 添加 MCP 依赖
uv add mcp

# 运行
uv run server.py

对应的配置文件改成:

{
  "mcpServers": {
    "weather": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/weather-mcp-server", "run", "server.py"]
    }
  }
}

常见问题 Q&A

Q1: 启动后 Claude 没有显示工具图标

大概率是配置文件路径写错了。检查:

  • JSON 格式有没有语法错误(多了少了逗号)
  • server.py 的路径是不是绝对路径
  • Python 是不是在系统 PATH 里(用 which pythonwhere python 检查)

Q2: 报错 “ModuleNotFoundError: No module named ‘mcp’”

说明 Claude Desktop 启动的 Python 环境跟你安装 mcp 的环境不是同一个。解决方案:

  • 用 uv 管理项目依赖(推荐)
  • 或者在配置里指定完整 Python 路径:
{
  "command": "/usr/local/bin/python3",
  "args": ["/path/to/server.py"]
}

Q3: Server 启动了但 AI 不调用工具

检查函数的 docstring 写得够不够清楚。AI 靠 docstring 理解工具用途,写得越具体越好:

  • ✅ “查询指定城市的天气信息,包括温度、湿度、风力”
  • ❌ “查天气”

Q4: 想连接真实天气 API 怎么办?

把 WEATHER_DATA 替换成真实的 API 调用。以和风天气为例:

@mcp.tool()
async def get_weather(city: str) -> str:
    """查询城市实时天气"""
    async with httpx.AsyncClient() as client:
        # 先查城市 ID
        geo_resp = await client.get(
            "https://geoapi.qweather.com/v2/city/lookup",
            params={"location": city, "key": "你的API_KEY"}
        )
        location_id = geo_resp.json()["location"][0]["id"]

        # 再查天气
        weather_resp = await client.get(
            "https://devapi.qweather.com/v7/weather/now",
            params={"location": location_id, "key": "你的API_KEY"}
        )
        now = weather_resp.json()["now"]
        return f"{city}: {now['temp']}°C, {now['text']}, 湿度{now['humidity']}%"

Q5: 怎么调试 MCP Server?

MCP 官方提供了 Inspector 工具:

npx @modelcontextprotocol/inspector python server.py

它会启动一个 Web 界面,你可以手动调用工具、查看资源,非常方便。

完整项目代码汇总

把所有代码整合到一个文件里,方便复制:

"""
MCP 天气查询 Server
功能:让 AI 助手能够查询城市天气信息
运行:python server.py
"""

from mcp.server.fastmcp import FastMCP

# ============================================================
# 1. 创建 Server 实例
# ============================================================
mcp = FastMCP(
    "weather-server",
    version="1.0.0",
    description="一个提供城市天气查询的 MCP Server"
)

# ============================================================
# 2. 数据源(可替换为真实 API)
# ============================================================
WEATHER_DB = {
    "北京": {"temp": 22, "condition": "晴", "humidity": 35},
    "上海": {"temp": 25, "condition": "多云", "humidity": 65},
    "广州": {"temp": 30, "condition": "阵雨", "humidity": 80},
    "深圳": {"temp": 29, "condition": "阴", "humidity": 75},
    "成都": {"temp": 20, "condition": "小雨", "humidity": 70},
    "杭州": {"temp": 24, "condition": "晴转多云", "humidity": 55},
    "武汉": {"temp": 26, "condition": "多云", "humidity": 60},
    "南京": {"temp": 23, "condition": "晴", "humidity": 50},
}

# ============================================================
# 3. 注册工具(Tools)
# ============================================================

@mcp.tool()
def get_weather(city: str) -> str:
    """查询指定城市的实时天气

    Args:
        city: 城市名称(中文),如 北京、上海、广州

    Returns:
        包含温度、天气状况、湿度的格式化字符串
    """
    data = WEATHER_DB.get(city)
    if not data:
        supported = ", ".join(WEATHER_DB.keys())
        return f"未找到「{city}」的天气数据。支持的城市:{supported}"

    return (
        f"📍 {city}当前天气\n"
        f"🌡️ 温度:{data['temp']}°C\n"
        f"🌤️ 状况:{data['condition']}\n"
        f"💧 湿度:{data['humidity']}%"
    )


@mcp.tool()
def compare_weather(city1: str, city2: str) -> str:
    """对比两个城市的天气

    Args:
        city1: 第一个城市名称
        city2: 第二个城市名称
    """
    d1 = WEATHER_DB.get(city1)
    d2 = WEATHER_DB.get(city2)

    if not d1:
        return f"未找到「{city1}」的天气数据"
    if not d2:
        return f"未找到「{city2}」的天气数据"

    diff = d1["temp"] - d2["temp"]
    warmer = city1 if diff > 0 else city2
    return (
        f"🌡️ 天气对比\n"
        f"{city1}{d1['temp']}°C, {d1['condition']}\n"
        f"{city2}{d2['temp']}°C, {d2['condition']}\n"
        f"👉 {warmer}更热,温差{abs(diff)}°C"
    )


# ============================================================
# 4. 注册资源(Resources)
# ============================================================

@mcp.resource("weather://cities")
def list_all_cities() -> str:
    """返回所有可查询的城市列表"""
    return "\n".join(WEATHER_DB.keys())


# ============================================================
# 5. 注册提示(Prompts)
# ============================================================

@mcp.prompt()
def weather_report_prompt(city: str) -> str:
    """生成天气报告的提示模板"""
    return f"请根据以下城市的天气数据,生成一份简洁的天气播报,适合发送给朋友:\n城市:{city}"


# ============================================================
# 6. 启动 Server
# ============================================================
if __name__ == "__main__":
    mcp.run()

总结

今天我们从零搭建了一个完整的 MCP Server,核心就三步:

  1. 装 SDKpip install mcp
  2. 写代码:用 @mcp.tool() 注册工具
  3. 配 Client:在 Claude Desktop 配置文件里加上你的 Server

整个过程其实不复杂,难的是想清楚「你想让 AI 能做什么」。MCP 只是一个通道,真正有价值的是你暴露给 AI 的能力。

下一步你可以:

  • 把 mock 数据换成真实 API(天气、股票、快递查询等)
  • 试试 Resources 和 Prompts 的高级用法
  • 用 SSE 模式搭建远程 MCP Server
  • 给多个 AI 应用共享同一个 Server

MCP 生态还在快速发展中,早点上手绝对不亏。有问题欢迎评论区交流!


参考资料:

  • MCP 官方文档:https://modelcontextprotocol.io
  • MCP Python SDK:https://github.com/modelcontextprotocol/python-sdk
  • MCP Server 示例合集:https://github.com/modelcontextprotocol/servers
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐