本文的教程来自于马克的技术工作坊的教学视频:MCP终极指南 - 带你深入掌握MCP(进阶篇)_哔哩哔哩_bilibili

由于教程中是mac系统,所以整理了用windows系统下遇到的问题以及解决办法

准备:uv的下载详细见上一篇博客;打开PowerShell;选择好并进入你希望文件所在的地址

1、首先跟着教程创建虚拟环境并激活环境(在PowerShell中,而不是cmd中)

ps:由于我电脑本身的python版本是3.9.13,视频中是3.13,MCP(Model Context Protocol)以及现代的 AI 工具开发,经常会用到 Python 3.10 及以上版本的新语法特性(例如新的类型注解 |、match-case 语法等)。如果你继续使用 3.9,在后续跟着视频写代码时,大概率会遇到语法报错。所以创建虚拟环境时,uv 会自动拉取 3.13 版本的 Python 并为你创建虚拟环境,完全不会干扰电脑上原来的 3.9 环境:

uv venv --python 3.13

报错一:在利用source激活虚拟环境时报错如上图:

报错原因: source 是 Mac/Linux 系统特有的命令,Windows 的 PowerShell 根本不认识它。此外,虚拟环境的文件夹结构在两个系统上也是不同的:Mac 是 .venv/bin/activate,而 Windows 是 .venv\Scripts\activate。

解决办法: 其实在图中,uv venv 成功执行后,系统已经贴心地给出了 Windows 下的激活提示(在 Activate with: 后面的绿色文字)。

在你的 PowerShell 中,直接输入以下命令并回车即可成功进入虚拟环境:

.venv\Scripts\activate

2、本身电脑上的python版本大于3.13的可以跳过这部分

报错二:安装MCP核心依赖时报错(电脑python版本大于3.13跳过这部分)

当安装uv add "mcp[cli]" httpx时会出现报错如下:

因为 uv 不仅仅是个虚拟环境工具,它还是一个项目包管理器。它的核心逻辑是:一切以 pyproject.toml 配置文件为准。

在你执行第一步 uv init weather_1 的时候,uv 自动检测到你电脑的全局环境是 Anaconda 3.9,于是它在生成的 pyproject.toml 文件里写下了一条规则:requires-python = ">=3.9"。

当你运行 uv add 时,uv 会强制去对齐这个配置文件。它发现你当前的虚拟环境是 3.13,跟它最初认定的 3.9 “不符”,于是它自作主张地删掉了你的 3.13 环境,降级回 3.9,然后尝试安装 mcp。结果当然就因为版本不够 3.10 而报错了。

解决办法:

1、第一步:修改配置 用记事本或者 VS Code 打开 weather_1 文件夹下的 pyproject.toml 文件。 找到这一行:

requires-python = ">=3.9"

修改为:

requires-python = ">=3.13"

2、第二步:更新固定版本(Pin version) 在你的 PowerShell 中,直接运行这行命令:

uv python pin 3.13

接下来就可以按照视频教程成功安装MCP核心依赖啦~

uv add "mcp[cli]" httpx

3、正式进入VS Code打开刚刚创建的weather_1文件夹(视频中是weather,我为了和基础篇创建的文件区分命名为了weather_1)

创建好weather.py文件夹之后,各部分解释如下:

  • 导入要用的各种包
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
  • FastMCP函数:能够帮助快速构建MCP服务器

传入的是正在创建的MCP Server的名称“weather”,将会返回一个对象,取名为mcp

# Initialize FastMCP server
mcp = FastMCP("weather", log_level="ERROR")
  • 导入两个常量

前者是美国气象局的地址;后者是请求数据时我们用的标识(表示我们是1.0版本的weather APP)

# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
  • 导入两个函数

这个用于请求天气数据:

async def make_nws_request(url: str) -> dict[str, Any] | None:
    """Make a request to the NWS API with proper error handling."""
    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:
            return None

这个用于对告警数据进行格式化:

def format_alert(feature: dict) -> str:
    """Format an alert feature into a readable string."""
    props = feature["properties"]
    return f"""
Event: {props.get('event', 'Unknown')}
Area: {props.get('areaDesc', 'Unknown')}
Severity: {props.get('severity', 'Unknown')}
Description: {props.get('description', 'No description available')}
Instructions: {props.get('instruction', 'No specific instructions provided')}
"""
  • 导入Tool

用于接收美国每个州的天气预警,参数是美国的州代码:

@mcp.tool()
async def get_alerts(state: str) -> str:
    """Get weather alerts for a US state.

    Args:
        state: Two-letter US state code (e.g. 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 "Unable to fetch alerts or no alerts found."

    if not data["features"]:
        return "No active alerts for this state."

    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)

另一个get_forecast函数,输入经纬度信息。

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """
    # First get the forecast grid endpoint
    #第一次调用URL,获取美国天气办公室信息
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    # Get the forecast URL from the points response
    #第二次调用,获取对应天气的URL
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    # Format the periods into a readable forecast
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # Only show next 5 periods
        forecast = f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}
Wind: {period['windSpeed']} {period['windDirection']}
Forecast: {period['detailedForecast']}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)

两个函数上面都有装饰器@mcp.tool():把函数注册为Tool,可以从函数的注释里面提取用途及参数的含义,使得模型能够决定调用这个函数的时机

  • 最后加入代码使得能运行
if __name__ == "__main__":
    # Initialize and run the server
    mcp.run(transport='stdio')

transport='stdio'表示MCP Server与Cline的沟通方式是MCP Server的标准输入输出

4、使用Cline注册配置好MCP Server,然后就可以提问了

{
  "mcpServers": {
    "weather":{
      "disabled": false,
      "timeout": 60,
      "command":"uv",
      "args": [
        "--directory",
        "/workspace/MCP/weather_1",#地址换成自己的
        "run",
        "weather.py"
      ],
      "transporType": "stdio"
    }
}

提问天气如何?模型正确输出回答了:(关于如何注册Cline,详细见UP主的这个视频:MCP终极指南 - 从原理到实战,带你深入掌握MCP(基础篇)_哔哩哔哩_bilibili,其中的大语言模型我选择接入的是阿里云百炼中赠送的免费token(注册后三个月内))

以上就完成啦!

以下是视频的后半部分内容,作者新建了一个mcp_logger.py文件来抓取MCP Server与Cline之间的对话究竟是怎样的,代码地址为:https://github.com/MarkTechStation/VideoCode/blob/main/MCP%E7%BB%88%E6%9E%81%E6%8C%87%E5%8D%97-%E8%BF%9B%E9%98%B6%E7%AF%87/weather/mcp_logger.py

接下来的内容推荐大家去看视频中的讲解,非常细致清晰

MCP Host:支持MCP协议的软件,例如使用到的Cline,Cursor,CherryStudio等

MCP Server:就是MCP服务器,是一种程序,里面含有各种Tool(其实是函数),每种功能对应一个Tool。

归根到底,MCP主要是函数的注册与使用,为了MCP Host与MCP Server之前的沟通,让模型感知到外部的环境中有哪些可以用的工具,让模型感知外部工具的一个协议,其实与模型没有太大的关系(下图红框部分)

下图中指的是常用的MCP Server与模型交互的方式,这里的方式和MCP没有太大关系

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐