主题
构建一个 MCP 服务端
开始构建你自己的服务端,以便在 Claude for Desktop 和其他客户端中使用。
在本教程中,我们将构建一个简单的 MCP 天气服务端,并将其连接到宿主 Claude for Desktop。
我们将要构建的内容
我们将构建一个暴露两个工具的服务端:get_alerts 和 get_forecast。然后我们将把该服务端连接到一个 MCP 宿主(在本例中为 Claude for Desktop):

NOTE
服务端可以连接到任何客户端。为简单起见,我们在此选择了 Claude for Desktop,但我们也有关于构建你自己的客户端的指南。
MCP 核心概念
MCP 服务端可以提供三种主要类型的能力:
本教程将主要聚焦于工具。
让我们开始构建我们的天气服务端
### 前置知识
本快速入门假设你熟悉:
* Python
* 像 Claude 这样的 LLM
### MCP 服务端中的日志记录
在实现 MCP 服务端时,请注意如何处理日志记录:
**对于基于 STDIO 的服务端:** 绝不要写入 stdout。写入 stdout 会破坏 JSON-RPC 消息并导致服务端崩溃。`print()` 函数默认写入 stdout,因此请将其完全排除在 STDIO 服务端之外。
**对于基于 HTTP 的服务端:** 标准输出日志记录没有问题,因为它不会干扰 HTTP 响应。
### 最佳实践
* 使用标准库 `logging` 模块,它写入 stderr。
* 使用 `logging.getLogger(__name__)` 为每个模块创建一个 logger,并在你的工具中调用它。
### 快速示例
```python
import logging
logger = logging.getLogger(__name__)
# ❌ Bad (STDIO)
print("Processing request")
# ✅ Good (STDIO)
logger.info("Processing request") # writes to stderr
```
### 系统要求
* 已安装 Python 3.10 或更高版本。
* 你必须使用 Python MCP SDK 2.0.0 或更高版本。
### 设置你的环境
首先,让我们安装 `uv` 并设置我们的 Python 项目和环境:
bash
curl -LsSf https://astral.sh/uv/install.sh | shpowershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"之后请务必重启终端,以确保 `uv` 命令被识别。
现在,让我们创建并设置我们的项目:
bash
# Create a new directory for our project
uv init weather
cd weather
# Create virtual environment and activate it
uv venv
source .venv/bin/activate
# Install dependencies
uv add "mcp[cli]"
# Create our server file
touch weather.pypowershell
# Create a new directory for our project
uv init weather
cd weather
# Create virtual environment and activate it
uv venv
.venv\Scripts\activate
# Install dependencies
uv add mcp[cli]
# Create our server file
new-item weather.py现在让我们深入构建你的服务端。
## 构建你的服务端
### 导入包并设置实例
将以下内容添加到你的 `weather.py` 顶部:
```python
from typing import Any
import httpx2
from mcp.server import MCPServer
# Initialize MCPServer
mcp = MCPServer("weather")
# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
```
`httpx2` 是 SDK 自身所依赖的 HTTP 客户端,因此安装 `mcp` 时已经将其引入。
MCPServer 类使用 Python 类型提示和文档字符串自动生成工具定义,使得创建和维护 MCP 工具变得容易。
### 辅助函数
接下来,让我们添加用于查询和格式化来自 National Weather Service API 数据的辅助函数:
```python
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 httpx2.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")}
"""
```
实现工具执行
工具执行处理器负责实际执行每个工具的逻辑。让我们添加它:
python
@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)运行服务端
最后,让我们初始化并运行服务端:
python
if __name__ == "__main__":
mcp.run(transport="stdio")你的服务端已完成!运行 uv run weather.py 来启动 MCP 服务端,它将监听来自 MCP 宿主的消息。
现在让我们从现有的 MCP 宿主 Claude for Desktop 测试你的服务端。
使用 Claude for Desktop 测试你的服务端
首先,确保你已安装 Claude for Desktop。你可以在此处安装最新版本。 如果你已经安装了 Claude for Desktop,请确保它已更新到最新版本。
我们需要为你想要使用的 MCP 服务端配置 Claude for Desktop。为此,请在文本编辑器中打开位于 ~/Library/Application Support/Claude/claude_desktop_config.json 的 Claude for Desktop 应用配置文件。如果文件不存在,请务必创建它。
例如,如果你安装了 VS Code:
bash
code ~/.config/Claude/claude_desktop_config.jsonbash
code ~/Library/Application\ Support/Claude/claude_desktop_config.jsonpowershell
code $env:AppData\Claude\claude_desktop_config.json然后你将在 mcpServers 键中添加你的服务端。只有当至少一个服务端被正确配置时,MCP UI 元素才会显示在 Claude for Desktop 中。
在本例中,我们将像这样添加我们唯一的天气服务端:
json
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
"run",
"weather.py"
]
}
}
}json
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather",
"run",
"weather.py"
]
}
}
}WARNING
你可能需要在 command 字段中放入 uv 可执行文件的完整路径。你可以通过在 macOS/Linux 上运行 which uv 或在 Windows 上运行 where uv 来获取它。
NOTE
确保传入服务端的绝对路径。你可以通过在 macOS/Linux 上运行 pwd 或在 Windows 命令提示符上运行 cd 来获取它。在 Windows 上,请记住在 JSON 路径中使用双反斜杠(\\)或正斜杠(/)。
这会告诉 Claude for Desktop:
- 有一个名为 "weather" 的 MCP 服务端
- 通过运行
uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py来启动它
保存文件,并重启 Claude for Desktop。
使用命令测试
让我们确认 Claude for Desktop 是否识别到了我们在 weather 服务端中暴露的两个工具。你可以通过查找 "Add files, connectors, and more /"
图标来做到这一点:

点击加号图标后,将鼠标悬停在 "Connectors" 菜单上。你应该会看到列出的 weather 服务端:

如果你的服务端没有被 Claude for Desktop 识别到,请前往故障排查部分查看调试提示。
如果服务端已出现在 "Connectors" 菜单中,你现在可以通过在 Claude for Desktop 中运行以下命令来测试你的服务端:
- What's the weather in Sacramento?
- What are the active weather alerts in Texas?


NOTE
由于这是美国国家气象局的服务,查询仅适用于美国境内的位置。
底层发生了什么
当你提出一个问题时:
- 客户端将你的问题发送给 Claude
- Claude 分析可用的工具并决定使用哪一个(些)
- 客户端通过 MCP 服务端执行选定的工具
- 结果被发送回 Claude
- Claude 组织出自然语言回复
- 回复展示给你!
故障排查
Claude for Desktop 集成问题
**从 Claude for Desktop 获取日志**
与 MCP 相关的 Claude.app 日志会写入 `~/Library/Logs/Claude`(macOS)或 `~/.config/Claude/logs/`(Linux)中的日志文件:
* `mcp.log` 将包含关于 MCP 连接和连接失败的一般日志。
* 名为 `mcp-server-SERVERNAME.log` 的文件将包含指定服务端的 stderr 输出。Stdio 服务端可能会将其所有日志都写入 stderr,因此这些文件不仅限于错误。
你可以运行以下命令来列出最近的日志并跟踪任何新日志:
```bash macOS
# Check Claude's logs for errors
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
```
```bash Linux
# Check Claude's logs for errors
tail -n 20 -f ~/.config/Claude/logs/mcp*.log
```
**服务端未显示在 Claude 中**
1. 检查你的 `claude_desktop_config.json` 文件语法
2. 确保你的项目路径是绝对路径而非相对路径
3. 完全重启 Claude for Desktop
WARNING
要正确重启 Claude for Desktop,你必须完全退出应用程序:
- Windows:右键单击系统托盘中的 Claude 图标(可能隐藏在 "hidden icons" 菜单中),然后选择 "Quit" 或 "Exit"。
- macOS:使用 Cmd+Q 或从菜单栏中选择 "Quit Claude"。
- Linux:右键单击系统托盘中的 Claude 图标并选择 "Quit",或在终端中运行
pkill -f claude-desktop。
仅仅关闭窗口并不会完全退出应用程序,你的 MCP 服务端配置更改将不会生效。
**工具调用静默失败**
如果 Claude 尝试使用工具但它们失败了:
1. 检查 Claude 的日志以查找错误
2. 验证你的服务端能够无错误地构建和运行
3. 尝试重启 Claude for Desktop
**这些都不起作用。我该怎么办?**
请参阅我们的[调试指南](https://modelcontextprotocol.io/docs/2026-07-28/tools/debugging)以获取更好的调试工具和更详细的指导。
Weather API 问题
错误:Failed to retrieve grid point data
这通常意味着以下情况之一:
- 坐标在美国境外
- NWS API 出现问题
- 你被限流了
修复方法:
- 验证你使用的是美国坐标
- 在请求之间添加少量延迟
- 检查 NWS API 状态页面
错误:No active alerts for [STATE]
这不是错误——它只是意味着该州当前没有天气预警。尝试其他州或在恶劣天气期间检查。
NOTE
如需更高级的故障排查,请查看我们的调试 MCP指南