MCP Server 实现一个 天气查询

Step1. 环境配置

安装 uv

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

Question: 什么是 uv 呢和 conda 比有什么区别?

Answer: 一个用 Rust 编写的超快速 (100x) Python 包管理器和环境管理工具,由 Astral 开发。定位为 pip 和 venv 的替代品,专注于速度、简单性和现代 Python 工作流。

创建项目目录

shell 复制代码
uv init mcp_server_test
shell 复制代码
cd mcp_server_test

创建虚拟环境并激活

shell 复制代码
uv venv
source .venv/bin/activate

安装依赖包

shell 复制代码
uv add "mcp[cli]" httpx requests

Step2. 实现 MCP Server

创建 weather.py

python 复制代码
import requests
from mcp.server.fastmcp import FastMCP


# 初始化 MCP 服务器
mcp = FastMCP("WeatherServer")

HEWEATHER_API_KEY = "你的 key"  # ← 填入你的和风天气Key 去https://dev.qweather.com/这里申请

def get_city_id(city_name: str) -> str:
    """根据中文城市名获取和风天气 location ID"""
    url = "https://geoapi.qweather.com/v2/city/lookup"
    params = {
        "location": city_name,
        "key": HEWEATHER_API_KEY
    }
    response = requests.get(url, params=params)
    data = response.json()
    if data.get("code") == "200" and data.get("location"):
        print(data)
        return data["location"][0]["id"]
    else:
        raise ValueError(f"找不到城市: {city_name},错误信息: {data}")


def get_weather(city_name: str) -> str:
    """根据城市中文名返回当前天气中文描述"""
    try:
        location_id = get_city_id(city_name)
        url = "https://devapi.qweather.com/v7/weather/now"
        params = {
            "location": location_id,
            "key": HEWEATHER_API_KEY
        }
        response = requests.get(url, params=params)
        data = response.json()
        if data.get("code") != "200":
            return f"天气查询失败:{data.get('code')}"
        now = data["now"]
        return (
            f"🌍 城市: {city_name}\n"
            f"🌤 天气: {now['text']}\n"
            f"🌡 温度: {now['temp']}°C\n"
            f"💧 湿度: {now['humidity']}%\n"
            f"🌬 风速: {now['windSpeed']} m/s\n"
        )
    except Exception as e:
        return f"查询出错:{str(e)}"

@mcp.tool('query_weather', '查询城市天气')
def query_weather(city: str) -> str:
    """
        输入指定城市的中文名称,返回当前天气查询结果。
        :param city: 城市名称
        :return: 格式化后的天气信息
        """
    return get_weather(city)


if __name__ == "__main__":
    # 以标准 I/O 方式运行 MCP 服务器
    mcp.run(transport='stdio')

Step3. 测试 MCP Server

运行测试

shell 复制代码
mcp dev weather.py

看到下面输出就启动成功了

text 复制代码
mcp dev weather.py
Starting MCP inspector...
Proxy server listening on port 3000

🔍 MCP Inspector is up and running at http://localhost:5173 🚀

Step4. 修改MCP Server 做成 SSE 服务

python 复制代码
import mcp.types as types
import requests
import uvicorn
from mcp.server.lowlevel import Server
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Mount, Route

# ================================
# 1) 你的和风天气API Key
# ================================
HEWEATHER_API_KEY = ""  # ← 填入你的和风天气Key(例如 "abc123xxxxxx")


# ================================
# 2) 查询天气核心逻辑
# ================================
def get_city_id(city_name: str) -> str:
    """根据中文城市名获取和风天气 location ID"""
    url = "https://geoapi.qweather.com/v2/city/lookup"
    params = {
        "location": city_name,
        "key": HEWEATHER_API_KEY
    }
    response = requests.get(url, params=params)
    data = response.json()
    if data.get("code") == "200" and data.get("location"):
        # 如果成功找到城市
        return data["location"][0]["id"]
    else:
        raise ValueError(f"找不到城市: {city_name},错误信息: {data}")


def get_weather(city_name: str) -> str:
    """根据城市中文名返回当前天气(中文描述、温度、湿度、风速)"""
    try:
        location_id = get_city_id(city_name)
        url = "https://devapi.qweather.com/v7/weather/now"
        params = {
            "location": location_id,
            "key": HEWEATHER_API_KEY
        }
        response = requests.get(url, params=params)
        data = response.json()
        if data.get("code") != "200":
            return f"天气查询失败:{data.get('code')}"

        now = data["now"]
        return (
            f"🌍 城市: {city_name}\n"
            f"🌤 天气: {now['text']}\n"
            f"🌡 温度: {now['temp']}°C\n"
            f"💧 湿度: {now['humidity']}%\n"
            f"🌬 风速: {now['windSpeed']} m/s\n"
        )
    except Exception as e:
        return f"查询出错:{str(e)}"


# ================================
# 3) MCP Server 定义
# ================================
app = Server("mcp-weather")

# (A) 工具调用处理器:根据工具名称选择执行逻辑
@app.call_tool()
async def call_tool_handler(
    name: str, arguments: dict
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    """
    MCP 工具调用处理器
    """
    if name == "query_weather":
        if "city" not in arguments:
            raise ValueError("Missing required argument 'city'")
        # 调用上面封装好的 get_weather
        weather_info = get_weather(arguments["city"])
        return [types.TextContent(type="text", text=weather_info)]
    else:
        raise ValueError(f"Unsupported tool name: {name}")


# (B) 工具列表:告知 MCP 端都有哪些可调用的工具
@app.list_tools()
async def list_tools() -> list[types.Tool]:
    """
    定义可用的 MCP 工具列表
    """
    return [
        types.Tool(
            name="query_weather",
            description="查询指定城市天气信息(基于和风天气API)",
            inputSchema={
                "type": "object",
                "required": ["city"],
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "要查询的城市名(中文)"
                    }
                },
            },
        ),
    ]


# ================================
# 4) SSE + Starlette 路由
# ================================
sse = SseServerTransport("/messages/")

async def handle_sse(request):
    """处理 /sse 路由的 SSE 连接,并将其接入 MCP Server。"""
    async with sse.connect_sse(
        request.scope, request.receive, request._send
    ) as streams:
        # 运行 MCP 应用,处理输入输出
        await app.run(
            streams[0], streams[1], app.create_initialization_options()
        )

starlette_app = Starlette(
    debug=True,
    routes=[
        Route("/sse", endpoint=handle_sse),
        Mount("/messages/", app=sse.handle_post_message),
    ],
)


# ================================
# 5) 启动服务器
# ================================
if __name__ == "__main__":
    uvicorn.run(starlette_app, host="127.0.0.1", port=8081)

Step5. 配置 Cherry Studio

安装 Cherry Studio

text 复制代码
https://cherry-ai.com/

配置模型 api

text 复制代码
https://api.baystoneai.com/
这里需要选择 工具 推理 这两项
然后是在这里选择你的 MCP 服务
接下来就可以对话啦,让我们看看测试效果
相关推荐
AI量化投资实验室3 分钟前
年化112.5%,最大回撤24.3%,卡玛比率4.62 | polars因子引擎重构完成(python源代码下载)
开发语言·python·重构
TGITCIC10 分钟前
智驱未来:AI大模型重构数据治理新范式
大模型·数据治理·ai agent·rag检索增强·mcp·大模型数据·ai数据
@蓝莓果粒茶20 分钟前
LeetCode第158题_用Read4读取N个字符 II
前端·c++·python·算法·leetcode·职场和发展·c#
Lilith的AI学习日记35 分钟前
n8n 中文系列教程_04.半开放节点深度解析:Code与HTTP Request高阶用法指南
大数据·人工智能·aigc·n8n
朴拙数科1 小时前
Stable Diffusion秋叶整合包V4独立版Python本地API连接指南
开发语言·python·stable diffusion
AI大模型顾潇1 小时前
[特殊字符] Prompt如何驱动大模型对本地文件实现自主变更:Cline技术深度解析
前端·人工智能·llm·微调·prompt·编程·ai大模型
berryyan1 小时前
FramePack for ComfyUI工作流Sage-Attention优化效率测试
aigc
袋鼠云数栈UED团队2 小时前
AI 大模型科普-概念向
人工智能·llm·aigc
明明跟你说过2 小时前
LangChain + 文档处理:构建智能文档问答系统 RAG 的实战指南
人工智能·python·语言模型·自然语言处理·chatgpt·langchain·gpt-3
几米哥2 小时前
Augment Code全面解析:新晋AI编程助手全面提升开发效率
aigc·visual studio code