一、MCP是什么?
MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 公司在 2024 年 11 月开源发布的一个开放协议。它的核心作用是让 AI 能够安全、标准化地连接和使用外部工具与数据,以消除碎片化集成、形成生态闭环。
二、两种MCP的传输通道
(1)本地通信:Stdio(标准输入/输出)
- 原理:当 AI 应用(如 VSCode 插件)和 MCP 服务在同一台电脑上时,客户端会直接把 MCP 服务当作一个子进程启动。两者通过操作系统的管道(stdin/stdout)直接"递纸条"沟通。
- 特点 :完全绕开了网络栈,延迟极低、配置简单,且数据不出本机,安全性高。
- 适用场景:本地开发调试、命令行工具、桌面 AI 助手(如读取本地文件、操作本地数据库)。
(2) 远程通信:Streamable HTTP(基于 HTTP 的流式传输)
- 原理:当 AI 应用和 MCP 服务不在同一台机器上(比如云端服务),它们通过 HTTP 协议进行跨网络通信。客户端发送 POST 请求,服务端通过长连接实时推送流式响应。
- 特点 :支持双向实时交互,天然支持高并发,且易于穿透企业防火墙。
- 适用场景:SaaS 应用集成、企业级多租户环境、需要实时推送数据的场景(如股票行情、实时监控)。
- 注:早期的 SSE(Server-Sent Events)传输方式因仅支持单向推送等局限,正逐渐被更强大的 Streamable HTTP 取代。
三、uvx和npx指令对应的环境安装
(1)uvx 的环境安装
a.安装python(版本在3.8以上)
pip install uv
b.未安装python-> 在 Windows 下,打开 PowerShell 执行官方一键安装脚本即可:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
(2)npx的环境安装
npx 是 Node.js 的包执行器,从 Node.js v8.2.0 开始就已经内置。
- 安装方式 :直接前往 Node.js 官网下载并安装 LTS(长期支持)版本(推荐 v18 或 v20+)。
四、天气查询实例

step1:采用uv创建一个虚拟环境
uv venv mcp-weather-example
step2:激活虚拟环境
mcp-weather-example\Scripts\activate
step3:初始化工程
uv init mcp-weather
step4:进入工程,并添加 MCP(Model Context Protocol)依赖包
cd .\mcp-weather\
uv add mcp
step5:servers的建立
# weather_server.py
from mcp.server.fastmcp import FastMCP
import httpx
from typing import Any
import warnings
warnings.filterwarnings("ignore", category=UserWarning, module="pydantic_settings")
# 1. 创建一个名为 "weather" 的 MCP Server 实例
mcp = FastMCP("weather")
API_KEY = "c1099b122d1b7d7bcd190e3cc3c5e1cb"
BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
USER_AGENT = "weather-app/1.0"
async def fetch_weather(city: str) -> dict[str, Any] | None:
params = {
"q": city,
"appid": API_KEY,
"units": "metric",
"lang": "zh_cn"
}
headers = {"User-Agent": USER_AGENT}
# 使用异步 HTTP 客户端发送请求
async with httpx.AsyncClient() as client:
try:
# 修正了这里的拼写错误:timout -> timeout
resp = await client.get(BASE_URL, params=params, headers=headers, timeout=30.0)
resp.raise_for_status() # 如果状态码不是 200,会抛出异常
return resp.json() # 返回字典格式的天气数据
except Exception:
return None # 发生任何错误,返回 None
def format_weather(data: dict[str, Any] | str) -> str:
# 1. 容错处理:如果传入的是字符串(比如错误信息),直接返回
if isinstance(data, str):
return data
# 2. 从字典中提取关键信息
try:
weather_desc = data["weather"][0]["description"] # 天气状况
temp = data["main"]["temp"] # 温度
humidity = data["main"]["humidity"] # 湿度
city = data["name"] # 城市名
# 3. 拼接成自然语言字符串
return f"{city} 当前天气:{weather_desc},气温 {temp}°C,湿度 {humidity}%"
except (KeyError, TypeError):
return "无法解析天气数据,请检查输入格式。"
@mcp.tool()
async def query_weather(city: str) -> str:
"""查询指定城市的当前天气。"""
data = await fetch_weather(city)
if data is None:
return f"抱歉,无法获取 {city} 的天气信息。"
return format_weather(data)
if __name__ == "__main__":
mcp.run(transport="stdio")
step6:建立client
import asyncio
import os
import json
from typing import Optional
from contextlib import AsyncExitStack
from openai import OpenAI
from dotenv import load_dotenv
# 修正拼写错误:StdioServerParamters -> StdioServerParameters
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# 1. 加载 .env 文件中的环境变量
# 这行代码会读取 .env 文件,并将其中的变量加载到系统环境变量中
load_dotenv()
async def main():
# 2. 初始化阿里云百炼客户端
# 使用 os.getenv() 从环境变量中获取 API Key
# 如果找不到变量,会返回 None,OpenAI 库会报错,提醒你检查配置
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="compatible-mode/v1"
)
# 3. 配置 MCP Server 连接参数
server_params = StdioServerParameters(
command="D:\\python.exe",
args=["e:\\mcp-servers-weather.py"]
)
# 4. 建立与 MCP Server 的连接
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# 5. 获取 Server 提供的工具列表,并转换为 OpenAI 格式
tools_response = await session.list_tools()
openai_tools = [
{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.inputSchema
}
}
for tool in tools_response.tools
]
# 6. 发送用户消息给大模型
messages = [{"role": "user", "content": "Shanghai weather today"}]
response = client.chat.completions.create(
model="qwen-max",
messages=messages,
tools=openai_tools,
tool_choice="auto"
)
# 7. 处理大模型的回复
message = response.choices[0].message
if message.tool_calls:
for tool_call in message.tool_calls:
if tool_call.function.name == "query_weather":
args = json.loads(tool_call.function.arguments)
result = await session.call_tool("query_weather", arguments=args)
messages.append(message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result.content[0].text
})
final_response = client.chat.completions.create(
model="qwen-max",
messages=messages
)
print("AI 最终回复:", final_response.choices[0].message.content)
else:
print("AI 回复:", message.content)
if __name__ == "__main__":
asyncio.run(main())