【大模型MCP协议】MCP官方文档(Model Context Protocol)一、开始——2. 快速入门——服务端开发者

https://modelcontextprotocol.io/quickstart/server

面向服务器开发者

开始构建你自己的服务器,以便在 Claude for Desktop 及其他客户端中使用。

在本教程中,我们将构建一个简单的 MCP 天气服务器,并将其连接到主机 Claude for Desktop。我们将从基础设置开始,然后逐步扩展到更复杂的用例。


我们将要构建什么

许多大语言模型(LLM)目前无法获取天气预报和严重天气警报。让我们用 MCP 来解决这个问题!

我们将构建一个服务器,暴露两个工具:get-alertsget-forecast。然后我们将把服务器连接到一个 MCP 主机(本例中为 Claude for Desktop):

在这里插入图片描述

在这里插入图片描述

注意: 服务器可以连接到任何客户端。这里我们选择 Claude for Desktop 只是为了简单起见,我们也有构建你自己的客户端的指南,以及其他客户端列表

为什么选择 Claude for Desktop 而不是 Claude.ai? 因为服务器是本地运行的,MCP 目前只支持桌面主机。远程主机正在积极开发中。

MCP 核心概念

MCP 服务器可以提供三种主要能力:

1. 资源(Resources):类似文件的数据,可以被客户端读取(如 API 响应或文件内容)

2. 工具(Tools):可以被 LLM 调用的函数(需用户批准)

3. 提示(Prompts):帮助用户完成特定任务的预设模板


本教程主要关注工具(Tools)。


Python

让我们开始构建天气服务器!完整代码可在此处查看。

前置知识

本快速入门假设你熟悉:

  • Python
  • 类似 Claude 的大语言模型

系统要求

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

环境搭建

首先,安装 uv 并设置 Python 项目和环境:

# MacOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

安装完成后,重启终端以确保 uv 命令可用。

现在,创建并设置项目:

# MacOS/Linux
uv init weather
cd weather

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

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

# 创建服务器文件
touch weather.py
# Windows
uv init weather
cd weather

uv venv
.venv\Scripts\activate

uv add mcp[cli] httpx

new-item 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 发起请求并进行错误处理。"""
    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:
    """获取美国某州的天气警报。

    参数:
        state: 两位美国州代码(如 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:
    """获取某地的天气预报。

    参数:
        latitude: 地点纬度
        longitude: 地点经度
    """
    # 首先获取预报网格端点
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "无法获取该地点的预报数据。"

    # 从 points 响应中获取预报 URL
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "无法获取详细预报。"

    # 格式化前 5 个时段的预报
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[: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 以确认一切正常。

在这里插入图片描述


完整代码(补充)

在这里插入图片描述

weather.py
####################################
# 导入所需的库和模块
####################################
from typing import Any  # 导入Any类型,用于类型提示
import httpx  # 导入httpx库,这是一个现代的异步HTTP客户端
from mcp.server.fastmcp import FastMCP  # 导入FastMCP,这是一个工具创建框架

####################################
# 初始化 FastMCP 服务器
####################################
# 创建一个名为"weather"的FastMCP实例,用于注册和管理工具
mcp = FastMCP("weather")  

####################################
# 定义常量
####################################
# 美国国家气象局API的基础URL
NWS_API_BASE = "https://api.weather.gov"
# 用户代理字符串,告诉API服务器是谁在请求数据
USER_AGENT = "weather-app/1.0"


####################################
# 工具函数
####################################
async def make_nws_request(url: str) -> dict[str, Any] | None:
    """向美国国家气象局(NWS) API发起请求并进行错误处理。
    
    参数:
        url: 完整的API请求URL
        
    返回:
        成功时返回JSON响应转换成的字典,失败时返回None
    """
    # 设置HTTP请求头
    headers = {
        "User-Agent": USER_AGENT,  # 用户代理,标识应用程序
        "Accept": "application/geo+json"  # 指定接受的响应格式为地理JSON
    }
    
    # 创建一个异步HTTP客户端会话
    async with httpx.AsyncClient() as client:
        try:
            # 发送GET请求,设置超时时间为30秒
            response = await client.get(url, headers=headers, timeout=30.0)
            # 如果状态码不是200系列,则抛出异常
            response.raise_for_status()
            # 将响应内容解析为JSON并返回
            return response.json()
        except Exception:
            # 如果发生任何错误(网络错误、超时、解析错误等),返回None
            return None


def format_alert(feature: dict) -> str:
    """将单个天气警报信息格式化为可读的字符串。
    
    参数:
        feature: API返回的单个警报特征字典
        
    返回:
        格式化后的警报信息字符串
    """
    # 从feature中获取properties字典,这里包含了警报的详细信息
    props = feature["properties"]
    
    # 使用f-string格式化警报信息
    # props.get('key', 'default')方法在key不存在时返回默认值
    return f"""
Event: {props.get('event', 'Unknown')}  # 警报事件类型,如暴风雨、洪水等
Area: {props.get('areaDesc', 'Unknown')}  # 受影响的地理区域描述
Severity: {props.get('severity', 'Unknown')}  # 严重程度,如Extreme、Severe等
Description: {props.get('description', 'No description available')}  # 详细描述
Instructions: {props.get('instruction', 'No specific instructions provided')}  # 官方建议和指导
"""


####################################
# API工具函数
####################################
@mcp.tool()  # 使用装饰器将函数注册为FastMCP工具
async def get_alerts(state: str) -> str:
    """获取美国某州的活跃天气警报。
    
    这个函数会连接到美国国家气象局API,获取指定州的所有活跃警报,
    并将它们格式化为易读的文本。

    参数:
        state: 两位美国州代码(如 CA表示加利福尼亚州, NY表示纽约州)
        
    返回:
        格式化后的警报信息字符串,或者错误消息
    """
    # 构建完整的API URL,用于获取特定州的活跃警报
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    
    # 调用之前定义的函数发送API请求
    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()  # 使用装饰器将函数注册为FastMCP工具
async def get_forecast(latitude: float, longitude: float) -> str:
    """获取指定地理坐标的天气预报。
    
    这个函数会先查询坐标对应的预报网格端点,然后获取详细预报,
    最后返回格式化的未来5个时段的天气预报。

    参数:
        latitude: 地点纬度坐标
        longitude: 地点经度坐标
        
    返回:
        格式化后的天气预报信息,或者错误消息
    """
    # 第一步:获取预报网格端点
    # NWS API需要先查询坐标对应的元数据,才能获取预报URL
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    # 检查是否成功获取元数据
    if not points_data:
        return "无法获取该地点的预报数据。"

    # 第二步:从元数据响应中提取预报URL
    # NWS API的响应中包含了用于获取预报的具体URL
    forecast_url = points_data["properties"]["forecast"]
    
    # 使用提取的URL获取详细预报
    forecast_data = await make_nws_request(forecast_url)

    # 检查是否成功获取预报
    if not forecast_data:
        return "无法获取详细预报。"

    # 第三步:从预报数据中提取需要的信息并格式化
    # 获取时段列表,每个时段代表一个预报周期(如今天白天、今晚等)
    periods = forecast_data["properties"]["periods"]
    
    # 创建一个空列表用于存储格式化后的预报
    forecasts = []
    
    # 只处理前5个时段的预报
    for period in periods[:5]:
        # 使用f-string格式化每个时段的预报
        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__":
    # 当直接运行此脚本时,初始化并启动FastMCP服务器
    # transport='stdio'表示使用标准输入/输出作为通信方式
    mcp.run(transport='stdio')


代码功能解释

这是一个天气服务API封装,使用Python编写,主要功能如下:

1. 代码结构:
  • 使用FastMCP框架创建了一个名为"weather"的服务
  • 定义了两个主要工具函数:get_alertsget_forecast
  • 包含辅助函数用于HTTP请求和格式化输出
2. 主要功能:
  • 连接美国国家气象局(NWS)的API获取天气数据
  • get_alerts函数:获取美国特定州的天气警报信息
  • get_forecast函数:根据经纬度获取特定地点的天气预报
3. 技术特点:
  • 使用异步HTTP请求(httpx库)提高性能
  • 使用类型注解确保代码类型安全
  • 包含错误处理机制,确保API请求失败时能优雅处理
总结

这个代码是一个简单的天气信息服务封装,可以集成到更大的应用程序中,为用户提供天气警报和预报功能。

使用 Claude for Desktop 测试服务器

注意: Claude for Desktop 目前不支持 Linux。Linux 用户可前往构建客户端教程,构建可连接到我们刚刚搭建的服务器的 MCP 客户端。

首先,确保你已安装 Claude for Desktop。点击此处下载安装最新版。 如果已安装,请确保已更新到最新版

你需要为想要使用的 MCP 服务器配置 Claude for Desktop。打开 ~/Library/Application Support/Claude/claude_desktop_config.json(MacOS/Linux)或 $env:AppData\Claude\claude_desktop_config.json(Windows)进行编辑。如果文件不存在请新建。

例如,若你已安装 VS Code

# MacOS/Linux
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
# Windows
code $env:AppData\Claude\claude_desktop_config.json

mcpServers 键下添加你的服务器。只有至少配置了一个服务器,Claude for Desktop 的 MCP UI 元素才会显示。

以天气服务器为例,配置如下:

(MacOS/Linux)

{
    "mcpServers": {
        "weather": {
            "command": "uv",
            "args": [
                "--directory",
                "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
                "run",
                "weather.py"
            ]
        }
    }
}

(Windows)

{
    "mcpServers": {
        "weather": {
            "command": "uv",
            "args": [
                "--directory",
                "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather",
                "run",
                "weather.py"
            ]
        }
    }
}

警告: 你可能需要在 command 字段中填写 uv 可执行文件的完整路径。可通过 which uv(MacOS/Linux)或 where uv(Windows)获取。

注意: 路径必须为绝对路径。

这告诉 Claude for Desktop:

  1. 有一个名为 “weather” 的 MCP 服务器
  2. 通过运行 uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py 启动它

保存文件并重启 Claude for Desktop


在Cursor里配置(补充)

配置参数

在这里插入图片描述

{
  "mcpServers": {
      "weather": {
          "command": "uv",
          "args": [
              "--directory",
              "C:\\Users\\Arnold\\Desktop\\test\\my-learning-test\\20250515_mcpTest_weather\\weather",
              "run",
              "weather.py"
          ]
      }
  }
}

注意:--directory需要传入一个目录(weather),uv会自动检测weather目录中的虚拟环境,并且激活后,执行run参数值指定的脚本(weather.py

检查mcp是否生效

在这里插入图片描述

按钮显示为绿色表示已生效。

提问和结果

在这里插入图片描述

注意:查看代码,该mcp会请求https://api.weather.gov/,如果自己电脑无法访问这个链接,那么mcp也请求不到,请先排查自己电脑情况!

Parameters
{
  "latitude": 34.0522,
  "longitude": -118.2437
}
Result

Tonight:
Temperature: 57°F
Wind: 0 to 10 mph SSE
Forecast: Mostly clear, with a low around 57. South southeast wind 0 to 10 mph.

---

Tuesday:
Temperature: 87°F
Wind: 0 to 10 mph SSW
Forecast: Sunny, with a high near 87. South southwest wind 0 to 10 mph.

---

Tuesday Night:
Temperature: 65°F
Wind: 0 to 10 mph S
Forecast: Mostly clear, with a low around 65. South wind 0 to 10 mph.

---

Wednesday:
Temperature: 89°F
Wind: 0 to 10 mph S
Forecast: Sunny, with a high near 89. South wind 0 to 10 mph.

---

Wednesday Night:
Temperature: 65°F
Wind: 0 to 10 mph SSE
Forecast: Mostly clear, with a low around 65. South southeast wind 0 to 10 mph.

Node

让我们开始构建天气服务器!完整代码可在此处查看。

前置知识

本快速入门假设你熟悉:

  • TypeScript
  • 类似 Claude 的大语言模型

系统要求

  • 请确保已安装最新版 Node

环境搭建

首先,安装 Node.js 和 npm(如未安装)。可从 nodejs.org 下载。验证安装:

node --version
npm --version

本教程需 Node.js 16 或更高版本。

创建并设置项目:

# MacOS/Linux
mkdir weather
cd weather

# 初始化 npm 项目
npm init -y

# 安装依赖
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript

# 创建文件
mkdir src
touch src/index.ts
# Windows
md weather
cd weather

npm init -y

npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript

md src
new-item src\index.ts

更新 package.json,添加 type: “module” 和 build 脚本:

{
  "type": "module",
  "bin": {
    "weather": "./build/index.js"
  },
  "scripts": {
    "build": "tsc && chmod 755 build/index.js"
  },
  "files": [
    "build"
  ]
}

在项目根目录创建 tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

构建你的服务器

导入包并初始化实例

src/index.ts 顶部添加如下内容:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// NWS API 基础地址
const NWS_API_BASE = "https://api.weather.gov";
// 用户代理字符串
const USER_AGENT = "weather-app/1.0";

// 创建 MCP 服务器实例,指定名称和版本
const server = new McpServer({
  name: "weather",
  version: "1.0.0",
  capabilities: {
    resources: {},
    tools: {},
  },
});
辅助函数

添加用于从美国国家气象局 API 查询和格式化数据的辅助函数:

// NWS API 请求辅助函数,返回泛型类型数据或 null
async function makeNWSRequest<T>(url: string): Promise<T | null> {
  const headers = {
    "User-Agent": USER_AGENT, // 设置用户代理
    Accept: "application/geo+json", // 设置接受的内容类型
  };

  try {
    // 发送 fetch 请求
    const response = await fetch(url, { headers });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    // 返回 JSON 数据
    return (await response.json()) as T;
  } catch (error) {
    // 捕获异常,输出错误日志
    console.error("Error making NWS request:", error);
    return null;
  }
}

// 警报特征接口定义
interface AlertFeature {
  properties: {
    event?: string;
    areaDesc?: string;
    severity?: string;
    status?: string;
    headline?: string;
  };
}

// 格式化警报数据为字符串
function formatAlert(feature: AlertFeature): string {
  const props = feature.properties;
  return [
    `Event: ${props.event || "Unknown"}`,
    `Area: ${props.areaDesc || "Unknown"}`,
    `Severity: ${props.severity || "Unknown"}`,
    `Status: ${props.status || "Unknown"}`,
    `Headline: ${props.headline || "No headline"}`,
    "---",
  ].join("\n");
}

// 预报时段接口定义
interface ForecastPeriod {
  name?: string;
  temperature?: number;
  temperatureUnit?: string;
  windSpeed?: string;
  windDirection?: string;
  shortForecast?: string;
}

// 警报响应接口
interface AlertsResponse {
  features: AlertFeature[];
}

// 网格点响应接口
interface PointsResponse {
  properties: {
    forecast?: string;
  };
}

// 预报响应接口
interface ForecastResponse {
  properties: {
    periods: ForecastPeriod[];
  };
}
工具执行实现

注册天气工具:

// 注册天气警报工具
server.tool(
  "get-alerts",
  "获取某州的天气警报",
  {
    state: z.string().length(2).describe("两位州代码(如 CA, NY)"),
  },
  async ({ state }) => {
    const stateCode = state.toUpperCase();
    const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
    const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);

    if (!alertsData) {
      return {
        content: [
          {
            type: "text",
            text: "获取警报数据失败",
          },
        ],
      };
    }

    const features = alertsData.features || [];
    if (features.length === 0) {
      return {
        content: [
          {
            type: "text",
            text: `该州暂无活跃警报:${stateCode}`,
          },
        ],
      };
    }

    // 格式化所有警报
    const formattedAlerts = features.map(formatAlert);
    const alertsText = `该州活跃警报:${stateCode}\n\n${formattedAlerts.join("\n")}`;

    return {
      content: [
        {
          type: "text",
          text: alertsText,
        },
      ],
    };
  },
);

// 注册天气预报工具
server.tool(
  "get-forecast",
  "获取某地的天气预报",
  {
    latitude: z.number().min(-90).max(90).describe("地点纬度"),
    longitude: z.number().min(-180).max(180).describe("地点经度"),
  },
  async ({ latitude, longitude }) => {
    // 获取网格点数据
    const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
    const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);

    if (!pointsData) {
      return {
        content: [
          {
            type: "text",
            text: `获取坐标网格点数据失败:${latitude}, ${longitude}。该地点可能不被 NWS API 支持(仅支持美国地区)。`,
          },
        ],
      };
    }

    const forecastUrl = pointsData.properties?.forecast;
    if (!forecastUrl) {
      return {
        content: [
          {
            type: "text",
            text: "无法从网格点数据获取预报 URL",
          },
        ],
      };
    }

    // 获取预报数据
    const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
    if (!forecastData) {
      return {
        content: [
          {
            type: "text",
            text: "获取预报数据失败",
          },
        ],
      };
    }

    const periods = forecastData.properties?.periods || [];
    if (periods.length === 0) {
      return {
        content: [
          {
            type: "text",
            text: "无可用预报时段",
          },
        ],
      };
    }

    // 格式化所有预报时段
    const formattedForecast = periods.map((period: ForecastPeriod) =>
      [
        `${period.name || "Unknown"}:`,
        `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
        `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
        `${period.shortForecast || "No forecast available"}`,
        "---",
      ].join("\n"),
    );

    const forecastText = `该地预报:${latitude}, ${longitude}\n\n${formattedForecast.join("\n")}`;

    return {
      content: [
        {
          type: "text",
          text: forecastText,
        },
      ],
    };
  },
);
运行服务器

实现主函数运行服务器:

// 主函数,启动 MCP 服务器
async function main() {
  const transport = new StdioServerTransport(); // 使用标准输入输出作为传输
  await server.connect(transport); // 连接服务器
  console.error("Weather MCP Server running on stdio");
}

main().catch((error) => {
  // 捕获主函数异常并输出
  console.error("Fatal error in main():", error);
  process.exit(1);
});

务必运行 npm run build 构建服务器!


使用 Claude for Desktop 测试服务器

配置方式与 Python 版一致,只需将 command 改为 nodeargs 填写绝对路径的 build/index.js


Java

注意: 这是基于 Spring AI MCP 自动配置和启动器的快速入门演示。手动创建同步和异步 MCP 服务器请参考 Java SDK Server 文档。

完整代码见 此处

系统要求

环境搭建

使用 Spring Initializer 启动项目。

添加如下依赖:

<!-- Maven -->
<dependencies>
      <dependency>
          <groupId>org.springframework.ai</groupId>
          <artifactId>spring-ai-starter-mcp-server</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
      </dependency>
</dependencies>
// Gradle
dependencies {
  implementation platform("org.springframework.ai:spring-ai-starter-mcp-server")
  implementation platform("org.springframework:spring-web")   
}

配置 application.properties 或 application.yml:

spring.main.bannerMode=off
logging.pattern.console=
logging:
  pattern:
    console:
spring:
  main:
    banner-mode: off

构建你的服务器

WeatherService.java

实现 WeatherService:

@Service
public class WeatherService {

    // REST 客户端,用于请求天气 API
    private final RestClient restClient;

    public WeatherService() {
        // 初始化 REST 客户端,设置基础地址和请求头
        this.restClient = RestClient.builder()
            .baseUrl("https://api.weather.gov")
            .defaultHeader("Accept", "application/geo+json")
            .defaultHeader("User-Agent", "WeatherApiClient/1.0 (your@email.com)")
            .build();
    }

    @Tool(description = "获取指定经纬度的天气预报")
    public String getWeatherForecastByLocation(
        double latitude,   // 纬度
        double longitude   // 经度
    ) {
        // 返回详细预报,包括温度、风速、风向、详细描述
        // 这里应实现具体的 API 调用和数据格式化逻辑
        return "";
    }

    @Tool(description = "获取美国某州的天气警报")
    public String getAlerts(
        @ToolParam(description = "两位美国州代码(如 CA, NY)") String state
    ) {
        // 返回活跃警报,包括事件类型、影响区域、严重程度、描述、安全指引
        // 这里应实现具体的 API 调用和数据格式化逻辑
        return "";
    }

    // 其他方法...
}
创建 Boot 应用
@SpringBootApplication
public class McpServerApplication {

    public static void main(String[] args) {
        // 启动 Spring Boot 应用
        SpringApplication.run(McpServerApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider weatherTools(WeatherService weatherService) {
        // 注册 WeatherService 中的工具方法
        return  MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
    }
}
运行服务器
./mvnw clean install

生成的 jar 文件在 target 目录下。


使用 Claude for Desktop 测试服务器

配置方式与 Python 版一致,只需将 command 改为 javaargs 填写绝对路径的 jar 文件。


Kotlin

完整代码见 此处

前置知识

  • Kotlin
  • 类似 Claude 的大语言模型

系统要求

  • 已安装 Java 17 或更高版本

环境搭建

安装 javagradle,可从 Oracle JDK 官网 下载。验证安装:

java --version

创建并设置项目:

# MacOS/Linux
mkdir weather
cd weather
gradle init
# Windows
md weather
cd weather
gradle init

选择 Application 类型,Kotlin 语言,Java 17 版本。

添加依赖:

// build.gradle.kts
val mcpVersion = "0.4.0"
val slf4jVersion = "2.0.9"
val ktorVersion = "3.1.1"

dependencies {
    implementation("io.modelcontextprotocol:kotlin-sdk:$mcpVersion")
    implementation("org.slf4j:slf4j-nop:$slf4jVersion")
    implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
    implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
}

添加插件:

plugins {
    kotlin("plugin.serialization") version "your_version_of_kotlin"
    id("com.github.johnrengelman.shadow") version "8.1.1"
}

构建你的服务器

实例初始化
// 运行 MCP 服务器主函数
fun `run mcp server`() {
    // 创建 MCP 服务器实例
    val server = Server(
        Implementation(
            name = "weather", // 工具名
            version = "1.0.0"
        ),
        ServerOptions(
            capabilities = ServerCapabilities(tools = ServerCapabilities.Tools(listChanged = true))
        )
    )

    // 使用标准 IO 创建传输
    val transport = StdioServerTransport(
        System.`in`.asInput(),
        System.out.asSink().buffered()
    )

    runBlocking {
        server.connect(transport) // 连接服务器
        val done = Job()
        server.onClose {
            done.complete() // 关闭时完成 job
        }
        done.join()
    }
}
天气 API 辅助函数
// 获取指定经纬度天气预报
suspend fun HttpClient.getForecast(latitude: Double, longitude: Double): List<String> {
    // 获取网格点信息
    val points = this.get("/points/$latitude,$longitude").body<Points>()
    // 获取预报信息
    val forecast = this.get(points.properties.forecast).body<Forecast>()
    // 格式化所有时段
    return forecast.properties.periods.map { period ->
        """
            ${period.name}:
            Temperature: ${period.temperature} ${period.temperatureUnit}
            Wind: ${period.windSpeed} ${period.windDirection}
            Forecast: ${period.detailedForecast}
        """.trimIndent()
    }
}

// 获取指定州天气警报
suspend fun HttpClient.getAlerts(state: String): List<String> {
    // 获取警报信息
    val alerts = this.get("/alerts/active/area/$state").body<Alert>()
    // 格式化所有警报
    return alerts.features.map { feature ->
        """
            Event: ${feature.properties.event}
            Area: ${feature.properties.areaDesc}
            Severity: ${feature.properties.severity}
            Description: ${feature.properties.description}
            Instruction: ${feature.properties.instruction}
        """.trimIndent()
    }
}
工具执行实现
// 创建 HTTP 客户端
val httpClient = HttpClient {
    defaultRequest {
        url("https://api.weather.gov")
        headers {
            append("Accept", "application/geo+json")
            append("User-Agent", "WeatherApiClient/1.0")
        }
        contentType(ContentType.Application.Json)
    }
    install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) }
}

// 注册获取警报工具
server.addTool(
    name = "get_alerts",
    description = "获取美国某州天气警报。输入为两位州代码(如 CA, NY)",
    inputSchema = Tool.Input(
        properties = buildJsonObject {
            putJsonObject("state") {
                put("type", "string")
                put("description", "两位美国州代码(如 CA, NY)")
            }
        },
        required = listOf("state")
    )
) { request ->
    val state = request.arguments["state"]?.jsonPrimitive?.content
    if (state == null) {
        return@addTool CallToolResult(
            content = listOf(TextContent("必须提供 'state' 参数。"))
        )
    }

    val alerts = httpClient.getAlerts(state)

    CallToolResult(content = alerts.map { TextContent(it) })
}

// 注册获取天气预报工具
server.addTool(
    name = "get_forecast",
    description = "获取指定经纬度的天气预报",
    inputSchema = Tool.Input(
        properties = buildJsonObject {
            putJsonObject("latitude") { put("type", "number") }
            putJsonObject("longitude") { put("type", "number") }
        },
        required = listOf("latitude", "longitude")
    )
) { request ->
    val latitude = request.arguments["latitude"]?.jsonPrimitive?.doubleOrNull
    val longitude = request.arguments["longitude"]?.jsonPrimitive?.doubleOrNull
    if (latitude == null || longitude == null) {
        return@addTool CallToolResult(
            content = listOf(TextContent("必须提供 'latitude' 和 'longitude' 参数。"))
        )
    }

    val forecast = httpClient.getForecast(latitude, longitude)

    CallToolResult(content = forecast.map { TextContent(it) })
}
运行服务器
fun main() = `run mcp server`()

使用 Claude for Desktop 测试服务器

配置方式与 Python 版一致,只需将 command 改为 javaargs 填写绝对路径的 jar 文件。


C#

完整代码见 此处

前置知识

  • C#
  • 类似 Claude 的大语言模型
  • .NET 8 或更高

系统要求

环境搭建

安装 dotnet,验证:

dotnet --version

创建并设置项目:

# MacOS/Linux
mkdir weather
cd weather
dotnet new console
# Windows
mkdir weather
cd weather
dotnet new console

添加 NuGet 包:

dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.Hosting

构建你的服务器

打开 Program.cs,替换为:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol;
using System.Net.Http.Headers;

// 创建主机构建器,避免多余输出
var builder = Host.CreateEmptyApplicationBuilder(settings: null);

// 注册 MCP 服务器及传输方式
builder.Services.AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();

// 注册 HttpClient 单例,设置基础地址和用户代理
builder.Services.AddSingleton(_ =>
{
    var client = new HttpClient() { BaseAddress = new Uri("https://api.weather.gov") };
    client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("weather-tool", "1.0"));
    return client;
});

var app = builder.Build();

// 启动应用
await app.RunAsync();

注意: 创建 ApplicationHostBuilder 时请用 CreateEmptyApplicationBuilder,以避免服务器向控制台输出额外信息(仅 STDIO 传输时需要)。

天气 API 工具类
using ModelContextProtocol.Server;
using System.ComponentModel;
using System.Net.Http.Json;
using System.Text.Json;

namespace QuickstartWeatherServer.Tools;

// 标记为 MCP 工具类型
[McpServerToolType]
public static class WeatherTools
{
    // 获取美国某州天气警报
    [McpServerTool, Description("获取美国某州天气警报。")]
    public static async Task<string> GetAlerts(
        HttpClient client,
        [Description("要获取警报的美国州。")] string state)
    {
        // 请求警报数据
        var jsonElement = await client.GetFromJsonAsync<JsonElement>($"/alerts/active/area/{state}");
        var alerts = jsonElement.GetProperty("features").EnumerateArray();

        if (!alerts.Any())
        {
            return "该州暂无活跃警报。";
        }

        // 格式化所有警报
        return string.Join("\n--\n", alerts.Select(alert =>
        {
            JsonElement properties = alert.GetProperty("properties");
            return $"""
                    Event: {properties.GetProperty("event").GetString()}
                    Area: {properties.GetProperty("areaDesc").GetString()}
                    Severity: {properties.GetProperty("severity").GetString()}
                    Description: {properties.GetProperty("description").GetString()}
                    Instruction: {properties.GetProperty("instruction").GetString()}
                    """;
        }));
    }

    // 获取某地的天气预报
    [McpServerTool, Description("获取某地的天气预报。")]
    public static async Task<string> GetForecast(
        HttpClient client,
        [Description("地点纬度。")] double latitude,
        [Description("地点经度。")] double longitude)
    {
        // 请求网格点数据
        var jsonElement = await client.GetFromJsonAsync<JsonElement>($"/points/{latitude},{longitude}");
        var periods = jsonElement.GetProperty("properties").GetProperty("periods").EnumerateArray();

        // 格式化所有时段
        return string.Join("\n---\n", periods.Select(period => $"""
                {period.GetProperty("name").GetString()}
                Temperature: {period.GetProperty("temperature").GetInt32()}°F
                Wind: {period.GetProperty("windSpeed").GetString()} {period.GetProperty("windDirection").GetString()}
                Forecast: {period.GetProperty("detailedForecast").GetString()}
                """));
    }
}
运行服务器
dotnet run

使用 Claude for Desktop 测试服务器

配置方式与 Python 版一致,只需将 command 改为 dotnetargs 填写 run 及项目绝对路径。


命令行测试

确保 Claude for Desktop 能识别我们在 weather 服务器中暴露的两个工具。你可以通过查找锤子图标来确认:

在这里插入图片描述

点击锤子图标后,你应该能看到两个工具:

在这里插入图片描述

如果服务器未被 Claude for Desktop 识别,请前往故障排查部分获取调试建议。

如果锤子图标已出现,你可以在 Claude for Desktop 中运行以下命令测试服务器:

  • What’s the weather in Sacramento?(萨克拉门托天气如何?)
  • What are the active weather alerts in Texas?(德州当前有哪些天气警报?)

在这里插入图片描述

在这里插入图片描述

注意: 由于这是美国国家气象局服务,查询仅适用于美国地区。


底层原理

当你提问时:

1. 客户端将你的问题发送给 Claude(大模型服务器)

2. Claude 分析可用工具并决定使用哪一个(或多个)

3. 客户端通过 MCP 服务器执行选定工具

4. 结果返回给 Claude

5. Claude 生成自然语言回复

6. 回复展示给你!


故障排查

Claude for Desktop 集成问题

获取 Claude for Desktop 日志

Claude.app 与 MCP 相关的日志写在 ~/Library/Logs/Claude

  • mcp.log 包含 MCP 连接及连接失败的通用日志
  • mcp-server-SERVERNAME.log 文件包含指定服务器的错误(stderr)日志

你可以用如下命令查看最新日志并实时跟踪:

# 检查 Claude 日志中的错误
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log

服务器未在 Claude 中显示

  1. 检查 claude_desktop_config.json 文件语法
  2. 确保项目路径为绝对路径
  3. 完全重启 Claude for Desktop

工具调用无响应

如果 Claude 尝试调用工具但失败:

  1. 检查 Claude 日志中的错误
  2. 确认服务器能正常构建和运行
  3. 尝试重启 Claude for Desktop

仍然无法解决?

请参考我们的调试指南获取更详细的调试工具和指导。

天气 API 问题

错误:无法获取网格点数据

通常原因如下:

  1. 坐标不在美国境内
  2. NWS API 出现问题
  3. 被限流

解决方法:

  • 确认使用的是美国坐标
  • 在请求间添加短暂延迟
  • 检查 NWS API 状态页

错误:该州暂无活跃警报

这不是错误,只是说明该州当前没有天气警报。可尝试其他州或在恶劣天气时再试。

更多高级故障排查,请参阅我们的调试 MCP 指南


后续步骤

主题说明
构建客户端学习如何构建可连接到你服务器的 MCP 客户端
示例服务器查看官方 MCP 服务器和实现的案例库
调试指南学习如何高效调试 MCP 服务器和集成
用 LLM 构建 MCP学习如何利用 Claude 等 LLM 加速 MCP 开发
### MCP Model Context Protocol Integration 的含义、定义与用途 #### 含义 MCPModel Context Protocol)Integration 是指通过模型关联协议MCP),实现不同系统之间高效的数据交互和功能集成的过程。它不仅限于简单的数据传输,还涉及上下文信息的传递以及复杂业务逻辑的处理[^1]。 #### 定义 MCP Integration 可被定义为种基于客户端-服务器架构的技术框架,用于支持大模型及其应用之间的无缝协作。该技术能够适应多种数据形式,并提供灵活的安全机制来保障通信过程中资源的有效管理和安全性[^3]。此外,其设计目标之就是引领 API 开发进入新的阶段,在此期间可以更充分地挖掘大型预训练语言模型的能力[^2]。 #### 用途 以下是几个主要方面展示了如何利用 MCP 进行系统间 或者服务间的整合: 1. **跨平台互操作性增强**: 使用标准接口使得不同的应用程序即使部署在异构环境中也能轻松完成任务调用和服务请求响应流程优化等工作; 2. **提高开发效率降低维护成本**: 借助预先构建好的组件库快速搭建原型或者生产环境下的解决方案;同时由于遵循统规范所以后期升级改动也相对简单快捷很多; 3. **加强隐私保护措施实施力度**: 内置的身份认证模块可以帮助企业更好地满足日益严格的法律法规要求比如GDPR等等规定下对于个人信息存储使用的限制条件; 4. **促进创新生态系统形成与发展**: 鼓励第三方开发者围绕核心产品线创造附加价值从而带动整个行业的进步速度加快技术创新步伐. 下面给出段 Python 实现示例代码展示了个基本版本的服务端接收来自客户端的消息并返回相应结果的功能片段: ```python import socket def mcp_server(host='localhost', port=9090): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: server_socket.bind((host, port)) server_socket.listen() while True: client_conn, addr = server_socket.accept() data = client_conn.recv(1024).decode('utf8') response = process_mcp_request(data) # Assume this function processes the request. client_conn.sendall(response.encode('utf8')) client_conn.close() finally: server_socket.close() if __name__ == "__main__": mcp_server() ``` 上述脚本创建了个监听指定地址端口等待连接到来然后读取发送过来的内容再经过内部函数转换后再反馈回去给对方关闭链接结束轮会话循环直到程序终止为止.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dontla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值