太炸裂,10分钟小白用Cursor开发自己的MCP服务器,赶紧学起来

在本教程中,我们将构建一个简易的 MCP 天气服务器(参考MCP官方文档),并将其与一个主机(客户端),即 Cursor 客户端相连接。

当前,许多大语言模型(LLM)尚不具备获取天气预报及恶劣天气警报的能力。我们将借助 MCP 来解决这一问题!

我们会构建一个服务器,该服务器将暴露两个工具:get-alertsget-forecast。随后,我们会把此服务器连接到一个 MCP 客户端。

众多编程语言都支持开发 MCP 服务器,例如 Python、JavaScript、Java、Kotlin、C# 等。在此,我们选用 Python 进行演示。

modelcontextprotocol.io/introductio... mcp 英文版官方文档

mcp-docs.cn/introductio... mcp 中文翻译官方文档

配套视频

www.bilibili.com/video/BV1JD...

搭建Python开发环境

首先,让我们安装 uvuv(Rust 版)需要 Python 3.8+ 环境:

通过 pip 安装(推荐):

bash 复制代码
pip install uv
# 检查是否安装成功
uv --version

以MacOS/Linux为例:

arduino 复制代码
curl -LsSf https://astral.sh/uv/install.sh | sh

以Windows为例:

arduino 复制代码
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

之后请务必重启你的终端,以确保 uv 命令被识别。

创建项目

现在,让我们创建并设置我们的项目:

以MacOS/Linux为例:

bash 复制代码
# 为我们的项目创建一个新 directory
uv init weather
cd weather

# 创建 virtual environment 并激活它
uv venv
source .venv/bin/activate

# 安装 dependencies
uv add "mcp[cli]" httpx

# 创建我们的 server file
touch weather.py

以Windows为例:

csharp 复制代码
# 为我们的项目创建一个新 directory
uv init weather
cd weather

# 创建 virtual environment 并激活它
uv venv
.venv\Scripts\activate

# 安装 dependencies
uv add mcp[cli] httpx

# 创建我们的 server file
new-item weather.py

现在让我们深入构建你的服务器。

服务器代码编写

将如下代码添加到你的 weather.py 文件的顶部:

ini 复制代码
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

# 初始化 FastMCP server
mcp = FastMCP("weather")

# Constants
# NWS(美国国家气象局) API 的基础 URL
NWS_API_BASE = "https://api.weather.gov"

# 用于标识我们的应用程序的 User-Agent 字符串
USER_AGENT = "weather-app/1.0"

让我们详细解释FastMCP类的功能和用法。FastMCP是一个用于构建工具服务器的框架,具有以下主要特点:

  1. 初始化
ini 复制代码
mcp = FastMCP("weather")

FastMCP实例化时需要一个名称参数,这里使用"weather"作为服务名称。这个名称用于标识该工具服务器。

  1. 工具装饰器

FastMCP提供了@mcp.tool()装饰器,用于将函数注册为工具。例如:

python 复制代码
@mcp.tool()
async def get_alerts(state: str) -> str:
    # 函数实现

这个装饰器将普通函数转换为可以通过MCP服务器调用的工具。

  1. 异步支持

FastMCP完全支持异步操作,可以处理异步函数(使用async/await语法)。这在处理I/O密集型操作(如API请求)时特别有用。

  1. 运行服务器
ini 复制代码
mcp.run(transport='stdio')

FastMCP提供了run()方法来启动服务器。可以指定不同的传输方式,这里使用'stdio'(标准输入输出)作为传输方式。

  1. 依赖管理

pyproject.toml文件可以看出,FastMCP是通过mcp[cli]包提供的,版本要求≥1.6.0:

ini 复制代码
dependencies = [
    "mcp[cli]>=1.6.0",
]

在这个天气应用中,FastMCP被用来:

  1. 创建一个天气服务工具服务器

  2. 提供两个主要工具函数:

    1. get_alerts: 获取特定州的天气警报
    2. get_forecast: 获取特定位置的天气预报
  3. 处理异步API请求

  4. 格式化和返回天气数据

查询天气和格式化函数

接下来这2个函数,用于查询和格式化来自 National Weather Service API 的数据:

python 复制代码
async def make_nws_request(url: str) -> dict[str, Any] | None:
    """向 NWS API 发送请求,并进行适当的错误处理。
    Args:
        url: NWS API 的完整请求 URL
        
    Returns:
        dict: 成功时返回解析后的 JSON 响应
        None: 请求失败时返回 None
    """
    # 设置请求头
    headers = {
        "User-Agent": USER_AGENT,  # 标识我们的应用
        "Accept": "application/geo+json"  # 指定期望的响应格式
    }
    
    # 创建异步 HTTP 客户端
    async with httpx.AsyncClient() as client:
        try:
            # 发送 GET 请求,设置30秒超时
            response = await client.get(url, headers=headers, timeout=30.0)
            # 检查响应状态码,非2xx状态码会抛出异常
            response.raise_for_status()
            # 解析并返回 JSON 响应
            return response.json()
        except Exception:
            # 捕获所有异常(网络错误、超时、JSON解析错误等)
            return None

def format_alert(feature: dict) -> str:
    """将警报 feature 格式化为可读的字符串。"""
    props = feature["properties"]
    return f"""
事件: {props.get('event', 'Unknown')}
区域: {props.get('areaDesc', 'Unknown')}
严重性: {props.get('severity', 'Unknown')}
描述: {props.get('description', 'No description available')}
指示: {props.get('instruction', 'No specific instructions provided')}
"""

编写2个工具函数

Tool 函数负责实际执行每个 tool 的逻辑。让我们添加它:

python 复制代码
@mcp.tool()
async def get_alerts(state: str) -> str:
    """获取美国州的天气警报。

    Args:
        state: 两个字母的美国州代码(例如 CA、NY)
    """
    # 构建获取指定州警报的API URL
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    # 发送请求获取警报数据
    data = await make_nws_request(url)

    # 检查响应是否有效且包含features字段
    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: 位置的经度
    """
    # 首先获取预报网格 endpoint
    # NWS API 需要先通过经纬度获取预报网格点信息
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    # 如果无法获取网格点数据,返回错误信息
    if not points_data:
        return "无法获取此位置的预报数据。"

    # 从网格点响应中提取预报URL
    # NWS API 的响应中包含了获取具体预报数据的URL
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    # 如果无法获取预报数据,返回错误信息
    if not forecast_data:
        return "无法获取详细预报。"

    # 从预报数据中提取时段信息并格式化
    # periods包含了不同时段(如"今天","今晚","明天"等)的预报
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    # 只显示未来5个时段的预报,避免信息过多
    for period in periods[:5]:  
        # 为每个时段构建格式化的预报字符串
        # 包含时段名称、温度、风向风速和详细预报
        forecast = f"""
{period['name']}:
温度: {period['temperature']}°{period['temperatureUnit']}
风: {period['windSpeed']} {period['windDirection']}
预报: {period['detailedForecast']}
"""
        forecasts.append(forecast)

    # 用分隔符连接所有预报,返回完整的预报文本
    return "\n---\n".join(forecasts)

运行服务器

最后,让我们初始化并运行 server:

ini 复制代码
if __name__ == "__main__":
    # 检查是否直接运行此文件
    # 初始化 MCP 服务器并使用标准输入输出(stdio)作为传输方式运行
    # stdio 传输方式允许通过标准输入输出流与其他程序进行通信
    mcp.run(transport='stdio')

Server 已经完成!运行 uv run weather.py 以确认一切正常。

现在让我们从现有的 MCP host(Cursor) 测试你的 server。

Cursor 连接你的Server

在Cursor中填写MCP的配置信息:

json 复制代码
{
    "mcpServers": {
        "weather": {
            "command": "uv",
            "args": [
                "--directory",
                "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
                "run",
                "weather.py"
            ]
        }
    }
}

这告诉 Cursor:

  1. 有一个名为 "weather" 的 MCP server。
  2. 通过运行 uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py 来启动它。

底层执行流程

当你通过客户端(Cursor)提出问题时:

  1. 客户端(client)将你的问题发送给 LLM;
  2. LLM 分析可用的 tools 并决定使用哪些 tool;
  3. 客户端(client) 通过 MCP server 执行选择的 tool;
  4. 结果被发回给 LLM;
  5. LLM 制定自然语言响应;
  6. 响应显示给你;
相关推荐
江小皮不皮8 小时前
为何选择MCP?自建流程与Anthropic MCP的对比分析
人工智能·llm·nlp·aigc·sse·mcp·fastmcp
爬呀爬的水滴1 天前
工具篇-如何在Github Copilot中使用MCP服务?
copilot·mcp
带刺的坐椅2 天前
jFinal 使用 SolonMCP 开发 MCP(拥抱新潮流)
java·ai·solon·jfinal·mcp
菜鸟分享录2 天前
MCP 入门实战:用 C# 开启 AI 新篇章
ai·c#·semantic kernel·mcp
全栈技术负责人2 天前
cursor对话关键词技巧
ai编程
小白跃升坊2 天前
1Panel + MaxKB 对接高德地图 MCP Server
mcp·max kb
犬余2 天前
模型上下文协议(MCP):AI的“万能插座”
人工智能·mcp
一个处女座的程序猿3 天前
LLMs之MCP:2025年5月2日,Anthropic 宣布 Claude 重大更新:集成功能上线,研究能力大幅提升
anthropic·mcp
带刺的坐椅3 天前
FastMCP(python)和 SolonMCP(java)的体验比较(不能说一样,但真的很像)
java·python·solon·mcp·fastmcp
零炻大礼包3 天前
【MCP】服务端搭建(python和uv环境搭建、nodejs安装、pycharma安装)
开发语言·python·uv·mcp