windows下自己动手写一个MCP Server之报错分析
本文的教程来自于马克的技术工作坊的教学视频: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没有太大关系

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



所有评论(0)