服务器开发
在本教程中,我们将构建一个简单的MCP天气服务器并将其连接到宿主应用程序Claude桌面版。我们将从基本设置开始,然后逐步进行到更复杂的用例。
我们将构建什么
许多大语言模型(包括Claude)目前没有获取天气预报和严重天气警报的能力。让我们使用MCP来解决这个问题!
我们将构建一个服务器,提供两个工具:get-alerts
和get-forecast
。然后我们将服务器连接到MCP宿主应用程序(在本例中是Claude桌面版):
为什么是Claude桌面版而不是Claude.ai?
MCP核心概念
MCP服务器可以提供三种主要类型的功能:
- 资源:类似文件的数据,可以被客户端读取(如API响应或文件内容)
- 工具:可以被大语言模型调用的函数(需要用户批准)
- 提示:预先编写的模板,帮助用户完成特定任务
本教程将主要关注工具。
让我们开始构建我们的天气服务器!您可以在这里找到我们将要构建的完整代码。
前提知识
本快速入门假设您熟悉:
- Python
- 像Claude这样的大语言模型
系统要求
- 安装Python 3.10或更高版本。
- 您必须使用Python MCP SDK 1.2.0或更高版本。
设置您的环境
首先,让我们安装uv
并设置我们的Python项目和环境:
安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
安装后请确保重启您的终端,以确保uv
命令被正确识别。
现在,让我们创建并设置我们的项目:
创建项目
# 为我们的项目创建一个新目录
uv init weather
cd weather
# 创建虚拟环境并激活它
uv venv
source .venv/bin/activate
# 安装依赖
uv add "mcp[cli]" httpx
# 创建我们的服务器文件
touch weather.py
# 创建我们的服务器文件
touch weather.py
现在让我们开始构建您的服务器。
构建您的服务器
导入包并设置实例
将这些添加到您的weather.py
顶部:
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
# 初始化FastMCP服务器
mcp = FastMCP("weather")
# 常量
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
FastMCP类使用Python类型提示和文档字符串自动生成工具定义,使创建和维护MCP工具变得简单。
辅助函数
接下来,让我们添加我们的辅助函数,用于查询和格式化来自国家气象服务API的数据:
async def make_nws_request(url: str) -> dict[str, Any] | None:
"""向NWS API发出GET请求,处理错误并返回JSON响应"""
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:
"""将警报特征格式化为可读字符串。"""
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')}
"""
实现工具执行
工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它:
@mcp.tool()
async def get_alerts(state: str) -> str:
"""获取指定州的天气警报(使用两字母州代码如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 "无法获取警报或未找到警报。"
if not data["features"]:
return "该州没有活动警报。"
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:
"""获取位置的天气预报。
Args:
latitude: 位置的纬度
longitude: 位置的经度
"""
# 首先获取预报网格端点
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return "无法为此位置获取预报数据。"
# 从点响应中获取预报URL
forecast_url = points_data["properties"]["forecast"]
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "无法获取详细预报。"
# 将时段格式化为可读预报
periods = forecast_data["properties"]["periods"]
forecasts = []
for period in periods[:5]: # 只显示接下来的5个时段
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)
运行服务器
最后,让我们初始化并运行服务器:
if __name__ == "__main__":
# 初始化并运行服务器
mcp.run(transport='stdio')
您的服务器已完成!运行uv run weather.py
以确认一切正常工作。
现在让我们使用现有的MCP宿主应用程序Claude桌面版测试您的服务器。
使用Claude桌面版测试您的服务器
首先,确保您已安装Claude桌面版。您可以在这里安装最新版本。 如果您已经安装了Claude桌面版,请确保它已更新到最新版本。
我们需要为您想要使用的任何MCP服务器配置Claude桌面版。为此,请在文本编辑器中打开您的Claude桌面版应用程序配置文件,位于~/Library/Application Support/Claude/claude_desktop_config.json
。如果该文件不存在,请创建它。
例如,如果您已安装VS Code:
打开配置文件
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
code %APPDATA%\Claude\claude_desktop_config.json
然后您将在mcpServers
键中添加您的服务器。只有在至少一个服务器正确配置的情况下,MCP UI元素才会在Claude桌面版中显示。
在这种情况下,我们将添加我们的单个天气服务器,如下所示:
配置Claude桌面版
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"ABSOLUTE_PATH_PLACEHOLDER",
"run",
"weather.py"
]
}
}
}
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather",
"run",
"weather.py"
]
}
}
}
command
字段中放入uv
可执行文件的完整路径。您可以通过在MacOS/Linux上运行which uv
或在Windows上运行where uv
来获取此路径。这告诉Claude桌面版:
- 有一个名为"weather"的MCP服务器
- 使用
uv
命令运行该服务器 - 在指定目录中运行服务器
- 使用
weather.py
作为入口点
现在,重启Claude桌面版。您应该会在工具栏中看到一个新的MCP图标。点击它,您将看到我们的天气工具!
下一步
恭喜!您已经成功构建了您的第一个MCP服务器。这只是开始 - 您可以:
让我们开始构建我们的天气服务器!您可以在这里找到我们将要构建的完整代码。
前提知识
本快速入门假设您熟悉:
- Node.js
- 像Claude这样的大语言模型
系统要求
- 安装Node.js 18或更高版本
- 您必须使用Node.js MCP SDK 1.2.0或更高版本
设置您的环境
首先,让我们创建一个新的Node.js项目:
创建项目
# 创建一个新目录
mkdir weather
cd weather
# 初始化项目
npm init -y
# 安装依赖
npm install @mcp/node node-fetch
# 创建我们的服务器文件
touch weather.js
现在让我们开始构建您的服务器。
构建您的服务器
导入包并设置实例
将这些添加到您的weather.js
顶部:
const { MCPServer } = require('@mcp/node');
const fetch = require('node-fetch');
// 初始化MCP服务器
const mcp = new MCPServer('weather');
// 常量
const NWS_API_BASE = 'https://api.weather.gov';
const USER_AGENT = 'weather-app/1.0';
辅助函数
接下来,让我们添加我们的辅助函数,用于查询和格式化来自国家气象服务API的数据:
async function makeNWSRequest(url) {
const headers = {
'User-Agent': USER_AGENT,
'Accept': 'application/geo+json'
};
try {
const response = await fetch(url, { headers });
if (!response.ok) throw new Error('API request failed');
return await response.json();
} catch (error) {
return null;
}
}
function formatAlert(feature) {
const props = feature.properties;
return `
Event: ${props.event || 'Unknown'}
Area: ${props.areaDesc || 'Unknown'}
Severity: ${props.severity || 'Unknown'}
Description: ${props.description || 'No description available'}
Instructions: ${props.instruction || 'No specific instructions provided'}
`;
}
实现工具执行
工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它:
// 获取警报工具
mcp.tool({
name: 'get-alerts',
description: '获取美国州的天气警报',
parameters: {
state: {
type: 'string',
description: '两字母美国州代码(例如CA、NY)'
}
},
async execute({ state }) {
const url = `${NWS_API_BASE}/alerts/active/area/${state}`;
const data = await makeNWSRequest(url);
if (!data || !data.features) {
return '无法获取警报或未找到警报。';
}
if (data.features.length === 0) {
return '该州没有活动警报。';
}
const alerts = data.features.map(formatAlert);
return alerts.join('\n---\n');
}
});
// 获取预报工具
mcp.tool({
name: 'get-forecast',
description: '获取位置的天气预报',
parameters: {
latitude: {
type: 'number',
description: '位置的纬度'
},
longitude: {
type: 'number',
description: '位置的经度'
}
},
async execute({ latitude, longitude }) {
// 首先获取预报网格端点
const pointsUrl = `${NWS_API_BASE}/points/${latitude},${longitude}`;
const pointsData = await makeNWSRequest(pointsUrl);
if (!pointsData) {
return '无法为此位置获取预报数据。';
}
// 从点响应中获取预报URL
const forecastUrl = pointsData.properties.forecast;
const forecastData = await makeNWSRequest(forecastUrl);
if (!forecastData) {
return '无法获取详细预报。';
}
// 将时段格式化为可读预报
const periods = forecastData.properties.periods;
const forecasts = periods.slice(0, 5).map(period => `
${period.name}:
Temperature: ${period.temperature}°${period.temperatureUnit}
Wind: ${period.windSpeed} ${period.windDirection}
Forecast: ${period.detailedForecast}
`);
return forecasts.join('\n---\n');
}
});
运行服务器
最后,让我们初始化并运行服务器:
// 初始化并运行服务器
mcp.start();
您的服务器已完成!运行node weather.js
以确认一切正常工作。
现在让我们使用现有的MCP宿主应用程序Claude桌面版测试您的服务器。
使用Claude桌面版测试您的服务器
首先,确保您已安装Claude桌面版。您可以在这里安装最新版本。 如果您已经安装了Claude桌面版,请确保它已更新到最新版本。
我们需要为您想要使用的任何MCP服务器配置Claude桌面版。为此,请在文本编辑器中打开您的Claude桌面版应用程序配置文件,位于~/Library/Application Support/Claude/claude_desktop_config.json
。如果该文件不存在,请创建它。
例如,如果您已安装VS Code:
打开配置文件
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
code $env:AppData\Claude\claude_desktop_config.json
然后您将在mcpServers
键中添加您的服务器。只有在至少一个服务器正确配置的情况下,MCP UI元素才会在Claude桌面版中显示。
在这种情况下,我们将添加我们的单个天气服务器,如下所示:
配置Claude桌面版
{
"mcpServers": {
"weather": {
"command": "node",
"args": [
"/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/weather.js"
]
}
}
}
{
"mcpServers": {
"weather": {
"command": "node",
"args": [
"C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather\\weather.js"
]
}
}
}
这告诉Claude桌面版:
- 有一个名为"weather"的MCP服务器
- 使用
node
命令运行该服务器 - 使用
weather.js
作为入口点
现在,重启Claude桌面版。您应该会在工具栏中看到一个新的MCP图标。点击它,您将看到我们的天气工具!
下一步
恭喜!您已经成功构建了您的第一个MCP服务器。这只是开始 - 您可以:
让我们开始构建我们的天气服务器!您可以在这里找到我们将要构建的完整代码。
前提知识
本快速入门假设您熟悉:
- Java
- 像Claude这样的大语言模型
系统要求
- 安装Java 17或更高版本
- 您必须使用Java MCP SDK 1.2.0或更高版本
设置您的环境
首先,让我们创建一个新的Maven项目。在您喜欢的IDE中创建一个新的Maven项目,或者使用以下命令:
创建项目
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=weather \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
然后,将以下依赖项添加到您的pom.xml
文件中:
<dependencies>
<dependency>
<groupId>dev.mcp</groupId>
<artifactId>mcp-java</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
现在让我们开始构建您的服务器。
构建您的服务器
创建主类
在src/main/java/com/example
目录中创建一个新的Weather.java
文件:
package com.example;
import dev.mcp.MCPServer;
import dev.mcp.Tool;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Weather {
private static final String NWS_API_BASE = "https://api.weather.gov";
private static final String USER_AGENT = "weather-app/1.0";
private static final HttpClient client = HttpClient.newHttpClient();
private static final ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) {
MCPServer mcp = new MCPServer("weather");
setupTools(mcp);
mcp.start();
}
private static void setupTools(MCPServer mcp) {
// 工具设置代码将在这里
}
}
辅助方法
在Weather
类中添加以下辅助方法:
private static Map<String, Object> makeNWSRequest(String url) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", USER_AGENT)
.header("Accept", "application/geo+json")
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
return null;
}
return mapper.readValue(response.body(), Map.class);
} catch (Exception e) {
return null;
}
}
private static String formatAlert(Map<String, Object> feature) {
Map<String, Object> props = (Map<String, Object>) feature.get("properties");
return String.format("""
Event: %s
Area: %s
Severity: %s
Description: %s
Instructions: %s
""",
props.getOrDefault("event", "Unknown"),
props.getOrDefault("areaDesc", "Unknown"),
props.getOrDefault("severity", "Unknown"),
props.getOrDefault("description", "No description available"),
props.getOrDefault("instruction", "No specific instructions provided"));
}
实现工具执行
现在让我们在setupTools
方法中实现我们的工具:
private static void setupTools(MCPServer mcp) {
// 获取警报工具
mcp.tool(new Tool.Builder()
.name("get-alerts")
.description("获取美国州的天气警报")
.parameter("state", "string", "两字母美国州代码(例如CA、NY)")
.execute(params -> {
String state = params.get("state").toString();
String url = String.format("%s/alerts/active/area/%s", NWS_API_BASE, state);
Map<String, Object> data = makeNWSRequest(url);
if (data == null || !data.containsKey("features")) {
return "无法获取警报或未找到警报。";
}
List<Map<String, Object>> features = (List<Map<String, Object>>) data.get("features");
if (features.isEmpty()) {
return "该州没有活动警报。";
}
return features.stream()
.map(Weather::formatAlert)
.collect(Collectors.joining("\n---\n"));
})
.build());
// 获取预报工具
mcp.tool(new Tool.Builder()
.name("get-forecast")
.description("获取位置的天气预报")
.parameter("latitude", "number", "位置的纬度")
.parameter("longitude", "number", "位置的经度")
.execute(params -> {
double latitude = Double.parseDouble(params.get("latitude").toString());
double longitude = Double.parseDouble(params.get("longitude").toString());
// 首先获取预报网格端点
String pointsUrl = String.format("%s/points/%f,%f", NWS_API_BASE, latitude, longitude);
Map<String, Object> pointsData = makeNWSRequest(pointsUrl);
if (pointsData == null) {
return "无法为此位置获取预报数据。";
}
// 从点响应中获取预报URL
Map<String, Object> properties = (Map<String, Object>) pointsData.get("properties");
String forecastUrl = properties.get("forecast").toString();
Map<String, Object> forecastData = makeNWSRequest(forecastUrl);
if (forecastData == null) {
return "无法获取详细预报。";
}
// 将时段格式化为可读预报
Map<String, Object> forecastProps = (Map<String, Object>) forecastData.get("properties");
List<Map<String, Object>> periods = (List<Map<String, Object>>) forecastProps.get("periods");
return periods.stream()
.limit(5)
.map(period -> String.format("""
%s:
Temperature: %s°%s
Wind: %s %s
Forecast: %s
""",
period.get("name"),
period.get("temperature"),
period.get("temperatureUnit"),
period.get("windSpeed"),
period.get("windDirection"),
period.get("detailedForecast")))
.collect(Collectors.joining("\n---\n"));
})
.build());
}
您的服务器已完成!运行mvn compile exec:java -Dexec.mainClass="com.example.Weather"
以确认一切正常工作。
现在让我们使用现有的MCP宿主应用程序Claude桌面版测试您的服务器。
使用Claude桌面版测试您的服务器
首先,确保您已安装Claude桌面版。您可以在这里安装最新版本。 如果您已经安装了Claude桌面版,请确保它已更新到最新版本。
我们需要为您想要使用的任何MCP服务器配置Claude桌面版。为此,请在文本编辑器中打开您的Claude桌面版应用程序配置文件,位于~/Library/Application Support/Claude/claude_desktop_config.json
。如果该文件不存在,请创建它。
例如,如果您已安装VS Code:
打开配置文件
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
code $env:AppData\Claude\claude_desktop_config.json
然后您将在mcpServers
键中添加您的服务器。只有在至少一个服务器正确配置的情况下,MCP UI元素才会在Claude桌面版中显示。
在这种情况下,我们将添加我们的单个天气服务器,如下所示:
配置Claude桌面版
{
"mcpServers": {
"weather": {
"command": "mvn",
"args": [
"compile",
"exec:java",
"-Dexec.mainClass=com.example.Weather",
"-f",
"/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/pom.xml"
]
}
}
}
{
"mcpServers": {
"weather": {
"command": "mvn",
"args": [
"compile",
"exec:java",
"-Dexec.mainClass=com.example.Weather",
"-f",
"C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather\\pom.xml"
]
}
}
}
这告诉Claude桌面版:
- 有一个名为"weather"的MCP服务器
- 使用
mvn
命令运行该服务器 - 在指定目录中运行服务器
- 使用
Weather
类作为入口点
现在,重启Claude桌面版。您应该会在工具栏中看到一个新的MCP图标。点击它,您将看到我们的天气工具!
下一步
恭喜!您已经成功构建了您的第一个MCP服务器。这只是开始 - 您可以:
测试命令
让我们确认Claude桌面端能正确识别天气服务中的两个工具。注意查看锤子图标
点击锤子图标后应该看到两个工具:
如果工具未显示,请参考故障排除章节。
成功显示工具后,可以在Claude桌面端测试以下命令:
- 萨克拉门托的天气如何?
- 德克萨斯州有哪些活跃的天气警报?
底层工作原理
问题处理流程:
- 客户端将问题发送给Claude
- Claude分析可用工具并选择使用
- 通过MCP服务器执行工具
- 返回结果给Claude
- Claude生成自然语言响应
- 向用户展示最终结果
故障排除
Claude桌面端集成问题
获取桌面端日志
日志文件位于~/Library/Logs/Claude
:
mcp.log
包含MCP连接日志mcp-server-SERVERNAME.log
包含指定服务器的错误日志
实时查看日志命令:
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
服务器未显示
- 检查claude_desktop_config.json文件语法
- 确认项目使用绝对路径
- 完全重启Claude桌面端
工具调用静默失败
- 检查Claude日志
- 验证服务器能否正常启动
- 尝试重启Claude桌面端
天气API问题
错误:无法获取网格点数据 可能原因:
- 坐标不在美国境内
- NWS API服务异常
- 触发速率限制
解决方案:
- 确认使用美国坐标
- 增加请求间隔时间
- 查看NWS API状态页