今天,让我们从零开始搭建我们自己的模型上下文协议(MCP)服务器。在本教程中,我将使用两个工具创建一个简单的模型上下文协议(MCP)服务器,并在Claude桌面应用程序中使用这些工具。
1. 搭建开发环境
这是本教程的文件结构。
.
├── ? venv/
├── ? helpers.py
├── ? server.py
└── ? tools.py
首先,让我们为我们的模型上下文协议(MCP)服务器创建一个虚拟环境。为了简便起见,我使用默认的 `venv` 工具来完成这项工作。但如果你愿意,你也可以使用像 `poetry` 或 `uv` 这样的 Python 包管理器。
# For Windows
python -m venv venv
venv\Scripts\activate
# For Linux
python3 -m venv venv
source venv\bin\activate
激活虚拟环境后,安装所需的依赖项。
pip install mcp[cli] httpx
2. 创建辅助函数
我们正在构建一个工具,用于获取指定地点的天气预报,以及另一个工具,用于获取美国特定州的天气警报。为了实现这一点,我们需要两个辅助函数。第一个函数将处理获取天气数据的 API 请求,第二个函数将对获取到的数据进行格式化。我使用 `httpx` 模块来进行 API 调用,但如果你愿意,也可以使用 `requests` 模块。第二个函数会对 API 调用返回的数据进行格式化。让我们创建 `helpers.py` 文件。
# helpers.py
from textwrap import dedent
import httpx
from typing import Any
import logging
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 as e:
logging.error(e)
return None
def format_alert(feature: dict) -> str:
"""Format an alert feature into a readable string."""
props = feature["properties"]
return dedent(
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')}
"""
)
3. 创建工具
既然我们已经有了辅助函数,那我们来创建一个 `tools.py` 文件,以便实现模型上下文协议(MCP)的工具。我们将在这些工具中使用那些辅助函数。确保在每个工具函数中都添加详细的文档字符串,清晰地描述该工具的功能。这些注释对于判断哪个工具适合特定任务来说至关重要。此外,函数名就作为工具的名称。在这种情况下,`get_alerts` 和 `get_forecast` 将是我们的工具名称。不过,如果你愿意,在将工具添加到服务器时,可以为你的工具赋予一个自定义的名称和描述。
这些工具的基本功能是使用一个辅助函数从天气 API 获取数据,再使用另一个辅助函数对数据进行格式化,然后返回数据。
# tools.py
from textwrap import dedent
from helpers import make_nws_request, format_alert
NWS_API_BASE = "https://api.weather.gov"
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}"
# Helper functoin call
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."
# Helper functoin call
alerts = [format_alert(feature) for feature in data["features"]]
return "\n---\n".join(alerts)
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}"
# Helper functoin call
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"]
# Helper functoin call
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 = dedent(
f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}
Wind: {period['windSpeed']} {period['windDirection']}
Forecast: {period['detailedForecast']}
"""
)
forecasts.append(forecast)
return "\n---\n".join(forecasts)
4. 创建服务器
好的。我们已经完成了模型上下文协议(MCP)工具的创建。现在,让我们创建 MCP 服务器,并将这些工具添加到服务器中。为此,我将创建 `server.py` 文件。在这里,由于这是一个本地服务器,我使用标准输入输出(stdio)方法来进行通信。
# server.py
from mcp.server.fastmcp import FastMCP
from tools import get_alerts, get_forecast
# Initialize FastMCP server
mcp = FastMCP("weather")
# Attach tools
# mcp.add_tool(get_alerts, name="Get-Weather-Alerts", description="TOOL DESC")
mcp.add_tool(get_alerts)
# mcp.add_tool(get_forecast, name="Get-Forecast", description="TOOL DESC")
mcp.add_tool(get_forecast)
if __name__ == "__main__":
#Run the server
mcp.run(transport='stdio')
我们给我们的模型上下文协议(MCP)服务器取个名字。在这种情况下,我将它命名为“weather”(天气)。接下来,我们把工具函数添加到服务器中。正如前面提到的,在这里你可以为你的工具传入一个自定义的名称和描述。不过,工具名称必须遵循以下规则:
- 只能包含字母和数字。
- 唯一允许的特殊字符是下划线(_)和连字符(-)。
- 必须至少包含一个字符。
- 最长不能超过 64 个字符。
最后,我们使用标准输入输出(stdio)传输方法来运行服务器。
5. 连接到 Claude 桌面应用程序
我们已经搭建好了模型上下文协议(MCP)服务器。现在我们可以将这个服务器与 Claude 桌面应用程序连接起来。为此,我们需要创建一个 JSON 配置文件。在以下位置创建一个 JSON 文件:C:\Users\USER>\AppData\Roaming\Claude\claude_desktop_config.json
{
"mcpServers": {
"weather": {
// Run python command within the virtual environment
// Absolute path to the python exe within the virtual envirnment
"command": "<PATH_TO_ENVIRONMENT>\\venv\\Scripts\\python",
"args": [
// Absolute path to server.py
"<PATH_TO_SERVER>\\server.py"
]
}
}
}
上述配置仅适用于这种特定情况。如果你使用诸如 Poetry 或 uv 之类的工具来管理虚拟环境,那么这种配置就不合适了。为了简化上述配置,设想你处于包含 server.py 文件的文件夹中。你可以使用 venv\Scripts\activate 命令激活虚拟环境,然后使用命令 python server.py 运行 server.py 文件。这个配置所做的事情是一样的。保存文件并重新启动 Claude 桌面应用程序。你无需手动运行服务器。
6. 测试模型上下文协议(MCP)服务器
如果你已正确完成上述所有步骤,那么在Claude桌面应用程序的输入区域右下角,你会看到一个锤子图标。点击该图标,就会显示可用工具的详细信息。
在这里,你可以看到我们的工具已列出来了。如前文所述,工具名称与函数名称相对应,而工具的描述则来自函数内部的文档字符串。此外,通过服务器名称,你可以看出该工具属于哪个服务器。在本教程中,我使用了单个服务器,但Claude桌面应用程序允许连接多个服务器。
如果你询问某个州的天气预报,Claude桌面应用程序会请求运行模型上下文协议(MCP)工具的权限。一旦你授予使用工具的权限,它就会执行该工具,并为你提供输出结果。
7. 故障排除
如果你没有正确遵循上述步骤,你可能会遇到类似这样的错误。
点击“打开模型上下文协议(MCP)设置”按钮,你将会看到另一个弹出窗口。
在这里,你可以看到在其中使用的命令和参数,这些是你在 JSON 配置文件中指定的。尝试在终端中使用这些参数运行此命令。如果出现错误,可能有两种原因:
JSON 配置错误
如果错误信息显示“系统找不到指定的路径”或“没有这样的文件或目录”,这意味着 server.py 文件的文件路径或虚拟环境中 python.exe 的文件路径不正确。仔细检查文件路径,然后重新启动 Claude 桌面应用程序。
MCP 服务器代码错误
如果你得到一个与 Python 相关的错误(以“Traceback”开头),这意味着 MCP 服务器的 Python 代码存在问题。检查 Python 文件中的错误,修复它们,然后重新启动 Claude 桌面应用程序。
8. 总结
我们首先做的是创建一个辅助函数,该函数以一个 URL 作为参数并返回 JSON 响应。我们还创建了另一个辅助函数,用于获取 JSON 字典并返回格式良好的字符串。在那之后,我们创建了两个工具。第一个工具获取美国某个州的天气警报。这个工具以美国的州代码作为参数,调用辅助函数获取天气警报,对其进行格式化,然后返回结果。第二个工具以经度和纬度作为参数,调用辅助函数获取天气预报,对其进行格式化,然后返回结果。接下来,我们创建了 MCP 服务器,并将我们的工具附加到该服务器上。然后,我们创建了一个 JSON 配置文件,用于将我们的 MCP 服务器与 Claude 桌面应用程序连接起来。当你询问特定地点的天气预报或美国某个州的天气警报时,Claude 会读取工具描述,从你的提示中提取所需的详细信息,将这些详细信息转换为适合该工具的正确格式,将它们传递给 MCP 工具,获取输出结果,并提供易于阅读的结果。