Skip to main content
在本教程中,我们将构建一个简单的 MCP 天气服务器并将其连接到主机 Claude for Desktop。

我们将构建什么

我们将构建一个服务器,暴露两个工具:get_alertsget_forecast。然后我们将服务器连接到 MCP 主机(在本例中是 Claude for Desktop):
服务器可以连接到任何客户端。我们在这里选择 Claude for Desktop 是为了简单起见,但我们也有关于构建您自己的客户端的指南以及此处其他客户端的列表

核心 MCP 概念

MCP 服务器可以提供三种主要类型的功能:
  1. 资源:客户端可以读取的文件式数据(如 API 响应或文件内容)
  2. 工具:LLM 可以调用的函数(需要用户批准)
  3. 提示:帮助用户完成特定任务的预写模板
本教程将主要关注工具。
  • Python
  • Node
  • Java
  • Kotlin
  • C#
让我们开始构建我们的天气服务器!您可以在此处找到我们将构建的完整代码。

先决知识

此快速入门假设您熟悉:
  • Python
  • Claude 等 LLM

MCP 服务器中的日志记录

在实现 MCP 服务器时,请注意如何处理日志记录:对于基于 STDIO 的服务器: 永远不要写入标准输出(stdout)。这包括:
  • Python 中的 print() 语句
  • console.log() in JavaScript
  • fmt.Println() in Go
  • Similar stdout functions in other languages
Writing to stdout will corrupt the JSON-RPC messages and break your server.For HTTP-based servers: Standard output logging is fine since it doesn’t interfere with HTTP responses.

Best Practices

  1. 使用写入 stderr 或文件的日志库。
  2. 工具名称应遵循此处指定的格式。

Quick Examples

# ❌ Bad (STDIO)
print("Processing request")

# ✅ Good (STDIO)
import logging
logging.info("Processing request")

System requirements

  • 已安装 Python 3.10 或更高版本。
  • 您必须使用 Python MCP SDK 1.2.0 或更高版本。

Set up your environment

首先,让我们安装 uv 并设置我们的 Python 项目和环境:
curl -LsSf https://astral.sh/uv/install.sh | sh
之后请确保重启终端,以确保 uv 命令被识别。现在,让我们创建并设置项目:
# 为我们的项目创建一个新目录
uv init weather
cd weather

# 创建虚拟环境并激活它
uv venv
source .venv/bin/activate

# 安装依赖
uv add "mcp[cli]" httpx

# 创建我们的服务器文件
touch weather.py
现在让我们深入构建您的服务器。

Building your server

Importing packages and setting up the instance

将这些添加到您的 weather.py 顶部:
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP("weather")

# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
FastMCP 类使用 Python 类型提示和文档字符串来自动生成工具定义,使创建和维护 MCP 工具变得容易。

Helper functions

接下来,让我们添加用于查询和格式化美国国家气象局 API 数据的辅助函数:
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')}
"""

Implementing tool execution

工具执行处理器负责实际执行每个工具的逻辑。让我们添加它:
@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)

@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
    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
    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)

Running the server

最后,让我们初始化并运行服务器:
def main():
    # Initialize and run the server
    mcp.run(transport='stdio')

if __name__ == "__main__":
    main()
您的服务器完成了!运行 uv run weather.py 来启动 MCP 服务器,它将监听来自 MCP 主机的消息。现在让我们使用现有的 MCP 主机 Claude for Desktop 来测试您的服务器。

Testing your server with Claude for Desktop

Claude for Desktop 尚未在 Linux 上可用。Linux 用户可以继续进行构建客户端教程来构建连接到我们刚构建的服务器的 MCP 客户端。
首先,确保您已安装 Claude for Desktop。您可以在此处安装最新版本。如果您已经安装了 Claude for Desktop,请确保它已更新到最新版本。我们需要为要使用的任何 MCP 服务器配置 Claude for Desktop。为此,请在文本编辑器中打开您的 Claude for Desktop 应用程序配置,位于 ~/Library/Application Support/Claude/claude_desktop_config.json。如果文件不存在,请确保创建它。例如,如果您安装了 VS Code
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
然后,您将在 mcpServers 键中添加您的服务器。只有在至少配置了一个服务器时,MCP UI 元素才会显示在 Claude for Desktop 中。在这种情况下,我们将像这样添加我们的单个天气服务器:
{
  "mcpServers": {
    "weather": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
        "run",
        "weather.py"
      ]
    }
  }
}
您可能需要在 command 字段中放置 uv 可执行文件的完整路径。您可以通过运行 which uv 在 macOS/Linux 上或 where uv 在 Windows 上获取此路径。
确保传入服务器的绝对路径。您可以通过运行 pwd 在 macOS/Linux 上或 cd 在 Windows 命令提示符上获取此路径。在 Windows 上,请记住要在 JSON 路径中使用双反斜杠 (\\) 或正斜杠 (/)。
这告诉 Claude for Desktop:
  1. 有一个名为 “weather” 的 MCP 服务器
  2. 通过运行 uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py 来启动它
保存文件,然后重新启动 Claude for Desktop

Test with commands

让我们确保 Claude for Desktop 正在获取我们在 weather 服务器中暴露的两个工具。您可以通过查找 “Search and tools” 图标来做到这一点:
点击滑块图标后,您应该看到两个工具列出:
如果您的服务器没有被 Claude for Desktop 获取,请继续进行故障排除部分以获取调试提示。 如果工具设置图标已显示,您现在可以通过在 Claude for Desktop 中运行以下命令来测试您的服务器:
  • 萨克拉门托的天气怎么样?
  • 德克萨斯州有哪些活跃的天气警报?
由于这是美国国家气象服务,查询将仅适用于美国地点。

What’s happening under the hood

当您提出问题时:
  1. 客户端将您的问题发送给 Claude
  2. Claude 分析可用的工具并决定使用哪些工具
  3. 客户端通过 MCP 服务器执行选定的工具
  4. 结果被发送回 Claude
  5. Claude 制定自然语言响应
  6. 响应显示给您!

Troubleshooting

Getting logs from Claude for DesktopClaude.app 与 MCP 相关的日志记录写入 ~/Library/Logs/Claude 中的日志文件:
  • mcp.log 将包含关于 MCP 连接和连接失败的一般日志记录。
  • 名为 mcp-server-SERVERNAME.log 的文件将包含来自命名服务器的错误(stderr)日志记录。
您可以运行以下命令来列出最近的日志并跟随任何新的日志:
# 检查 Claude 的日志是否有错误
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
Server not showing up in Claude
  1. 检查您的 claude_desktop_config.json 文件语法
  2. 确保项目路径是绝对路径而不是相对路径
  3. 完全重新启动 Claude for Desktop
要正确重新启动 Claude for Desktop,您必须完全退出应用程序:
  • Windows:右键单击系统托盘中的 Claude 图标(可能隐藏在”隐藏图标”菜单中)并选择”退出”或”退出”。
  • macOS:使用 Cmd+Q 或从菜单栏选择”退出 Claude”。
仅关闭窗口不会完全退出应用程序,您的 MCP 服务器配置更改不会生效。
Tool calls failing silently如果 Claude 尝试使用工具但失败:
  1. 检查 Claude 的日志是否有错误
  2. 验证您的服务器构建和运行没有错误
  3. 尝试重新启动 Claude for Desktop
None of this is working. What do I do?请参考我们的调试指南以获取更好的调试工具和更详细的指导。
Error: Failed to retrieve grid point data这通常意味着:
  1. 坐标在美国以外
  2. NWS API 有问题
  3. 您被限制速率
修复:
  • 验证您使用的是美国坐标
  • 在请求之间添加小延迟
  • 检查 NWS API 状态页面
Error: No active alerts for [STATE]这不是错误 - 它只是意味着该州目前没有天气警报。尝试不同的州或在恶劣天气期间检查。
有关更高级的故障排除,请查看我们的调试 MCP指南

Next steps

I