> ## Documentation Index
> Fetch the complete documentation index at: https://model-context-protocol.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 为服务器开发者

> 开始构建您自己的服务器，以便在 Claude for Desktop 和其他客户端中使用。

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

### 我们将构建什么

许多 LLM（包括 Claude）目前无法获取天气预报和严重天气警报。让我们使用 MCP 来解决这个问题！

我们将构建一个暴露两个工具的服务器：`get-alerts` 和 `get-forecast`。然后我们将服务器连接到 MCP 主机（在本例中为 Claude for Desktop）：

<Frame>
  <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/weather-alerts.png?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=7377055662d8860b9834a60e612cae9d" width="2809" height="1850" data-path="images/weather-alerts.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/current-weather.png?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=0f7aa65433b72be5ce3e5c463ca90f3a" width="2780" height="1849" data-path="images/current-weather.png" />
</Frame>

<Note>
  服务器可以连接到任何客户端。我们在这里选择了 Claude for Desktop 以简化操作，但我们也有关于[构建您自己的客户端](/quickstart/client)以及[其他客户端列表](/clients)的指南。
</Note>

<Accordion title="为什么选择 Claude for Desktop 而不是 Claude.ai？">
  由于服务器是本地运行的，MCP 目前仅支持桌面主机。远程主机正在积极开发中。
</Accordion>

### 核心 MCP 概念

MCP 服务器可以提供三种主要类型的功能：

1. **资源**：可以被客户端读取的类似文件的数据（如 API 响应或文件内容）
2. **工具**：可以由 LLM 调用的函数（需要用户批准）
3. **提示**：帮助用户完成特定任务的预编写模板

本教程将主要关注工具。

<Tabs>
  <Tab title="Python">
    让我们开始构建我们的天气服务器吧！[您可以在此处找到我们将构建的完整代码。](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-python)

    ### 先决知识

    本快速入门假设您熟悉：

    * Python
    * LLMs 如 Claude

    ### 系统要求

    对于 Python，请确保您安装了 Python 3.9 或更高版本。

    ### 设置您的环境

    首先，让我们安装 `uv` 并设置我们的 Python 项目和环境：

    <CodeGroup>
      ```bash MacOS/Linux theme={null}
      curl -LsSf https://astral.sh/uv/install.sh | sh
      ```

      ```powershell Windows theme={null}
      powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
      ```
    </CodeGroup>

    确保在此之后重新启动您的终端，以确保 `uv` 命令被识别。

    现在，让我们创建并设置我们的项目：

    <CodeGroup>
      ```bash MacOS/Linux theme={null}
      # 创建一个新目录用于我们的项目
      uv init weather
      cd weather

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

      # 安装依赖项
      uv add mcp httpx 

      # 删除模板文件
      rm hello.py

      # 创建我们的文件
      mkdir -p src/weather
      touch src/weather/__init__.py
      touch src/weather/server.py
      ```

      ```powershell Windows theme={null}
      # 创建一个新目录用于我们的项目
      uv init weather
      cd weather

      # 创建虚拟环境并激活它
      uv venv
      .venv\Scripts\activate

      # 安装依赖项
      uv add mcp httpx

      # 清理样板代码
      rm hello.py

      # 创建我们的文件
      md src
      md src\weather
      new-item src\weather\__init__.py
      new-item src\weather\server.py
      ```
    </CodeGroup>

    将此代码添加到 `pyproject.toml`：

    ```toml theme={null}
    ...rest of config

    [build-system]
    requires = [ "hatchling",]
    build-backend = "hatchling.build"

    [project.scripts]
    weather = "weather:main"
    ```

    将此代码添加到 `__init__.py`：

    ```python src/weather/__init__.py theme={null}
    from . import server
    import asyncio

    def main():
        """包的主入口点。"""
        asyncio.run(server.main())

    # 可选地在包级别公开其他重要项目
    __all__ = ['main', 'server']
    ```

    现在让我们深入构建您的服务器。

    ## 构建您的服务器

    ### 导入包

    将这些添加到 `server.py` 的顶部：

    ```python theme={null}
    from typing import Any
    import asyncio
    import httpx
    from mcp.server.models import InitializationOptions
    import mcp.types as types
    from mcp.server import NotificationOptions, Server
    import mcp.server.stdio
    ```

    ### 设置实例

    然后初始化服务器实例和 NWS API 的基本 URL：

    ```python theme={null}
    NWS_API_BASE = "https://api.weather.gov"
    USER_AGENT = "weather-app/1.0"

    server = Server("weather")
    ```

    ### 实现工具列表

    我们需要告诉客户端有哪些工具可用。`list_tools()` 装饰器注册此处理程序：

    ```python theme={null}
    @server.list_tools()
    async def handle_list_tools() -> list[types.Tool]:
        """
        列出可用工具。
        每个工具使用 JSON Schema 验证指定其参数。
        """
        return [
            types.Tool(
                name="get-alerts",
                description="获取某个州的天气警报",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "state": {
                            "type": "string",
                            "description": "两字母州代码（例如 CA，NY）",
                        },
                    },
                    "required": ["state"],
                },
            ),
            types.Tool(
                name="get-forecast",
                description="获取某个位置的天气预报",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "latitude": {
                            "type": "number",
                            "description": "位置的纬度",
                        },
                        "longitude": {
                            "type": "number",
                            "description": "位置的经度",
                        },
                    },
                    "required": ["latitude", "longitude"],
                },
            ),
        ]

    ```

    这定义了我们的两个工具：`get-alerts` 和 `get-forecast`。

    ### 辅助函数

    接下来，让我们添加用于查询和格式化来自国家气象局 API 的数据的辅助函数：

    ```python theme={null}
    async def make_nws_request(client: httpx.AsyncClient, url: str) -> dict[str, Any] | None:
        """向 NWS API 发出请求并进行适当的错误处理。"""
        headers = {
            "User-Agent": USER_AGENT,
            "Accept": "application/geo+json"
        }

        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"事件: {props.get('event', '未知')}\n"
            f"区域: {props.get('areaDesc', '未知')}\n"
            f"严重性: {props.get('severity', '未知')}\n"
            f"状态: {props.get('status', '未知')}\n"
            f"标题: {props.get('headline', '无标题')}\n"
            "---"
        )
    ```

    ### 实现工具执行

    工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它：

    ```python theme={null}
    @server.call_tool()
    async def handle_call_tool(
        name: str, arguments: dict | None
    ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        """
        处理工具执行请求。
        工具可以获取天气数据并通知客户端更改。
        """
        if not arguments:
            raise ValueError("缺少参数")
      
        if name == "get-alerts":
            state = arguments.get("state")
            if not state:
                raise ValueError("缺少 state 参数")

            # 将 state 转换为大写以确保格式一致
            state = state.upper()
            if len(state) != 2:
                raise ValueError("state 必须是两字母代码（例如 CA，NY）")

            async with httpx.AsyncClient() as client:
                alerts_url = f"{NWS_API_BASE}/alerts?area={state}"
                alerts_data = await make_nws_request(client, alerts_url)

                if not alerts_data:
                    return [types.TextContent(type="text", text="无法检索警报数据")]

                features = alerts_data.get("features", [])
                if not features:
                    return [types.TextContent(type="text", text=f"{state} 没有活动警报")]

                # 将每个警报格式化为简洁的字符串
                formatted_alerts = [format_alert(feature) for feature in features[:20]] # 仅取前 20 个警报
                alerts_text = f"{state} 的活动警报:\n\n" + "\n".join(formatted_alerts)

                return [
                    types.TextContent(
                        type="text",
                        text=alerts_text
                    )
                ]
        elif name == "get-forecast":
            try:
                latitude = float(arguments.get("latitude"))
                longitude = float(arguments.get("longitude"))
            except (TypeError, ValueError):
                return [types.TextContent(
                    type="text",
                    text="无效的坐标。请提供有效的纬度和经度数字。"
                )]
                
            # 基本坐标验证
            if not (-90 <= latitude <= 90) 或 not (-180 <= longitude <= 180):
                return [types.TextContent(
                    type="text",
                    text="无效的坐标。纬度必须在 -90 到 90 之间，经度在 -180 到 180 之间。"
                )]

            async with httpx.AsyncClient() as client:
                # 首先获取网格点
                lat_str = f"{latitude}"
                lon_str = f"{longitude}"
                points_url = f"{NWS_API_BASE}/points/{lat_str},{lon_str}"
                points_data = await make_nws_request(client, points_url)

                if not points_data:
                    return [types.TextContent(type="text", text=f"无法检索坐标的网格点数据：{latitude}, {longitude}。此位置可能不受 NWS API 支持（仅支持美国位置）。")]

                # 从响应中提取预报 URL
                properties = points_data.get("properties", {})
                forecast_url = properties.get("forecast")
                
                if not forecast_url:
                    return [types.TextContent(type="text", text="无法从网格点数据中获取预报 URL")]

                # 获取预报
                forecast数据 = await make_nws_request(client, forecast_url)
                
                if not forecast数据:
                    return [types.TextContent(type="text", text="无法检索预报数据")]

                # 格式化预报期
                periods = forecast数据.get("properties", {}).get("periods", [])
                if not periods:
                    return [types.TextContent(type="text", text="没有可用的预报期")]

                # 将每个期格式化为简洁的字符串
                formatted_forecast = []
                for period in periods:
                    forecast_text = (
                        f"{period.get('name', '未知')}:\n"
                        f"温度: {period.get('temperature', '未知')}°{period.get('temperatureUnit', 'F')}\n"
                        f"风: {period.get('windSpeed', '未知')} {period.get('windDirection', '')}\n"
                        f"{period.get('shortForecast', '无可用预报')}\n"
                        "---"
                    )
                    formatted_forecast.append(forecast_text)

                forecast_text = f"{latitude}, {longitude} 的预报:\n\n" + "\n".join(formatted_forecast)

                return [types.TextContent(
                    type="text",
                    text=forecast_text
                )]
        else:
            raise ValueError(f"未知工具: {name}")
    ```

    ### 运行服务器

    最后，实现运行服务器的主函数：

    ```python theme={null}
    async def main():
        # 使用 stdin/stdout 流运行服务器
        async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
            await server.run(
                read_stream,
                write_stream,
                InitializationOptions(
                    server_name="weather",
                    server_version="0.1.0",
                    capabilities=server.get_capabilities(
                        notification_options=NotificationOptions(),
                        experimental_capabilities={},
                    ),
                ),
            )

    # 如果您想连接到自定义客户端，这是必需的
    if __name__ == "__main__":
        asyncio.run(main())
    ```

    您的服务器已完成！运行 `uv run src/weather/server.py` 以确认一切正常。

    现在让我们从现有的 MCP 主机 Claude for Desktop 测试您的服务器。

    ## 使用 Claude for Desktop 测试您的服务器

    <Note>
      Claude for Desktop 尚不支持 Linux。Linux 用户可以继续[构建客户端](/quickstart/client)教程，以构建一个连接到我们刚刚构建的服务器的 MCP 客户端。
    </Note>

    首先，确保您已安装 Claude for Desktop。[您可以在此处安装最新版本。](https://claude.ai/download) 如果您已经有 Claude for Desktop，请**确保它已更新到最新版本。**

    我们需要为您想要使用的 MCP 服务器配置 Claude for Desktop。为此，请在文本编辑器中打开您的 Claude for Desktop 应用配置 `~/Library/Application Support/Claude/claude_desktop_config.json`。如果文件不存在，请确保创建它。

    例如，如果您安装了 [VS Code](https://code.visualstudio.com/)：

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash theme={null}
        code ~/Library/Application\ Support/Claude/claude_desktop_config.json
        ```
      </Tab>

      <Tab title="Windows">
        ```powershell theme={null}
        code $env:AppData\Claude\claude_desktop_config.json
        ```
      </Tab>
    </Tabs>

    然后，您将在 `mcpServers` 键中添加您的服务器。只有在至少一个服务器配置正确时，Claude for Desktop 中的 MCP UI 元素才会显示。

    在本例中，我们将添加我们的单个天气服务器，如下所示：

    <Tabs>
      <Tab title="MacOS/Linux">
        ```json Python theme={null}
        {
            "mcpServers": {
                "weather": {
                    "command": "uv",
                    "args": [
                        "--directory",
                        "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
                        "run",
                        "weather"
                    ]
                }
            }
        }
        ```
      </Tab>

      <Tab title="Windows">
        ```json Python theme={null}
        {
            "mcpServers": {
                "weather": {
                    "command": "uv",
                    "args": [
                        "--directory",
                        "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather",
                        "run",
                        "weather"
                    ]
                }
            }
        }
        ```
      </Tab>
    </Tabs>

    <Note>
      确保传递给服务器的路径是绝对路径。
    </Note>

    这告诉 Claude for Desktop：

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

    保存文件，并重新启动 **Claude for Desktop**。
  </Tab>

  <Tab title="Node">
    让我们开始构建我们的天气服务器吧！[您可以在此处找到我们将构建的完整代码。](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-typescript)

    ### 先决知识

    本快速入门假设您熟悉：

    * TypeScript
    * LLMs 如 Claude

    ### 系统要求

    对于 TypeScript，请确保您安装了最新版本的 Node。

    ### 设置您的环境

    首先，让我们安装 Node.js 和 npm（如果您还没有安装）。您可以从 [nodejs.org](https://nodejs.org/) 下载它们。
    验证您的 Node.js 安装：

    ```bash theme={null}
    node --version
    npm --version
    ```

    对于本教程，您需要 Node.js 版本 16 或更高版本。

    现在，让我们创建并设置我们的项目：

    <CodeGroup>
      ```bash MacOS/Linux theme={null}
      # 创建一个新目录用于我们的项目
      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
      ```

      ```powershell Windows theme={null}
      # 创建一个新目录用于我们的项目
      md weather
      cd weather

      # 初始化一个新的 npm 项目
      npm init -y

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

      # 创建我们的文件
      md src
      new-item src\index.ts
      ```
    </CodeGroup>

    更新您的 package.json 以添加 type: "module" 和一个构建脚本：

    ```json package.json theme={null}
    {
      "type": "module",
      "bin": {
        "weather": "./build/index.js"
      },
      "scripts": {
        "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
      },
      "files": [
        "build"
      ],
    }
    ```

    在项目根目录中创建一个 `tsconfig.json`：

    ```json tsconfig.json theme={null}
    {
      "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` 的顶部：

    ```typescript theme={null}
    import { Server } from "@modelcontextprotocol/sdk/server/index.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    import {
      CallToolRequestSchema,
      ListToolsRequestSchema,
    } from "@modelcontextprotocol/sdk/types.js";
    import { z } from "zod";
    ```

    ### 设置实例

    然后初始化 NWS API 基本 URL、验证模式和服务器实例：

    ```typescript theme={null}
    const NWS_API_BASE = "https://api.weather.gov";
    const USER_AGENT = "weather-app/1.0";

    // 定义 Zod 验证模式
    const AlertsArgumentsSchema = z.object({
      state: z.string().length(2),
    });

    const ForecastArgumentsSchema = z.object({
      latitude: z.number().min(-90).max(90),
      longitude: z.number().min(-180).max(180),
    });

    // 创建服务器实例
    const server = new Server(
      {
        name: "weather",
        version: "1.0.0",
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );
    ```

    ### 实现工具列表

    我们需要告诉客户端有哪些工具可用。此 `server.setRequestHandler` 调用将为我们注册此列表：

    ```typescript theme={null}
    // 列出可用工具
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "get-alerts",
            description: "获取某个州的天气警报",
            inputSchema: {
              type: "object",
              properties: {
                state: {
                  type: "string",
                  description: "两字母州代码（例如 CA，NY）",
                },
              },
              required: ["state"],
            },
          },
          {
            name: "get-forecast",
            description: "获取某个位置的天气预报",
            inputSchema: {
              type: "object",
              properties: {
                latitude: {
                  type: "number",
                  description: "位置的纬度",
                },
                longitude: {
                  type: "number",
                  description: "位置的经度",
                },
              },
              required: ["latitude", "longitude"],
            },
          },
        ],
      };
    });
    ```

    这定义了我们的两个工具：`get-alerts` 和 `get-forecast`。

    ### 辅助函数

    接下来，让我们添加用于查询和格式化来自国家气象局 API 的数据的辅助函数：

    ```typescript theme={null}
    // 用于发出 NWS API 请求的辅助函数
    async function makeNWSRequest<T>(url: string): Promise<T | null> {
      const headers = {
        "User-Agent": USER_AGENT,
        Accept: "application/geo+json",
      };

      try {
        const response = await fetch(url, { headers });
        if (!response.ok) {
          throw new Error(`HTTP 错误！状态：${response.status}`);
        }
        return (await response.json()) as T;
      } catch (error) {
        console.error("发出 NWS 请求时出错：", 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 [
        `事件: ${props.event || "未知"}`,
        `区域: ${props.areaDesc || "未知"}`,
        `严重性: ${props.severity || "未知"}`,
        `状态: ${props.status || "未知"}`,
        `标题: ${props.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[];
      };
    }
    ```

    ### 实现工具执行

    工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它：

    ```typescript theme={null}
    // 处理工具执行
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      try {
        if (name === "get-alerts") {
          const { state } = AlertsArgumentsSchema.parse(args);
          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).slice(0, 20) // 仅取前 20 个警报；
          const alertsText = `${stateCode} 的活动警报：\n\n${formattedAlerts.join(
            "\n"
          )}`;

          return {
            content: [
              {
                  type: "text",
                  text: alertsText,
              },
            ],
          };
        } else if (name === "get-forecast") {
          const { latitude, longitude } = ForecastArgumentsSchema.parse(args);

          // 获取网格点数据
          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 || "未知"}:`,
              `温度: ${period.temperature || "未知"}°${
                period.temperatureUnit || "F"
              }`,
              `风: ${period.windSpeed || "未知"} ${
                period.windDirection || ""
              }`,
              `${period.shortForecast || "无可用预报"}`,
              "---",
            ].join("\n")
          );

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

          return {
            content: [
              {
                type: "text",
                text: forecastText,
              },
            ],
          };
        } else {
          throw new Error(`未知工具：${name}`);
        }
      } catch (error) {
        if (error instanceof z.ZodError) {
          throw new Error(
            `无效的参数：${error.errors
              .map((e) => `${e.path.join(".")}: ${e.message}`)
              .join(", ")}`
          );
        }
        throw error;
      }
    });
    ```

    ### 运行服务器

    最后，实现运行服务器的主函数：

    ```typescript theme={null}
    // 启动服务器
    async function main() {
      const transport = new StdioServerTransport();
      await server.connect(transport);
      console.error("Weather MCP 服务器在 stdio 上运行");
    }

    main().catch((error) => {
      console.error("main() 中的致命错误：", error);
      process.exit(1);
    });
    ```

    确保运行 `npm run build` 以构建您的服务器！这是使您的服务器连接的非常重要的一步。

    现在让我们从现有的 MCP 主机 Claude for Desktop 测试您的服务器。

    ## 使用 Claude for Desktop 测试您的服务器

    <Note>
      Claude for Desktop 尚不支持 Linux。Linux 用户可以继续[构建客户端](/quickstart/client)教程，以构建一个连接到我们刚刚构建的服务器的 MCP 客户端。
    </Note>

    首先，确保您已安装 Claude for Desktop。[您可以在此处安装最新版本。](https://claude.ai/download) 如果您已经有 Claude for Desktop，请**确保它已更新到最新版本。**

    我们需要为您想要使用的 MCP 服务器配置 Claude for Desktop。为此，请在文本编辑器中打开您的 Claude for Desktop 应用配置 `~/Library/Application Support/Claude/claude_desktop_config.json`。如果文件不存在，请确保创建它。

    例如，如果您安装了 [VS Code](https://code.visualstudio.com/)：

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash theme={null}
        code ~/Library/Application\ Support/Claude/claude_desktop_config.json
        ```
      </Tab>

      <Tab title="Windows">
        ```powershell theme={null}
        code $env:AppData\Claude\claude_desktop_config.json
        ```
      </Tab>
    </Tabs>

    然后，您将在 `mcpServers` 键中添加您的服务器。只有在至少一个服务器配置正确时，Claude for Desktop 中的 MCP UI 元素才会显示。

    在本例中，我们将添加我们的单个天气服务器，如下所示：

    <Tabs>
      <Tab title="MacOS/Linux">
        <CodeGroup>
          ```json Node  theme={null}
          {
              "mcpServers": {
                  "weather": {
                      "command": "node",
                      "args": [
                          "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js"
                      ]
                  }
              }
          }
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Windows">
        <CodeGroup>
          ```json Node theme={null}
          {
              "mcpServers": {
                  "weather": {
                      "command": "node",
                      "args": [
                          "C:\\PATH\\TO\\PARENT\\FOLDER\\weather\\build\\index.js"
                      ]
                  }
              }
          }
          ```
        </CodeGroup>
      </Tab>
    </Tabs>

    这告诉 Claude for Desktop：

    1. 有一个名为 "weather" 的 MCP 服务器
    2. 通过运行 `node /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js` 启动它

    保存文件，并重新启动 **Claude for Desktop**。
  </Tab>
</Tabs>

### 使用命令进行测试

让我们确保 Claude for Desktop 正在拾取我们在 `weather` 服务器中公开的两个工具。您可以通过查找锤子 <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/claude-desktop-mcp-hammer-icon.svg?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=42936bf1e7a50a5e612adf929c128b79" style={{display: 'inline', margin: 0, height: '1.3em'}} width="32" height="32" data-path="images/claude-desktop-mcp-hammer-icon.svg" /> 图标来执行此操作：

<Frame>
  <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/visual-indicator-mcp-tools.png?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=8edbcff81e44477ba2afc6ba7c1713c6" width="1358" height="272" data-path="images/visual-indicator-mcp-tools.png" />
</Frame>

点击锤子图标后，您应该会看到列出的两个工具：

<Frame>
  <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/available-mcp-tools.png?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=487309df172c84fb084609abedd2fff9" width="1048" height="604" data-path="images/available-mcp-tools.png" />
</Frame>

如果您的服务器未被 Claude for Desktop 拾取，请转到[故障排除](#troubleshooting)部分以获取调试提示。

如果锤子图标已显示，您现在可以通过在 Claude for Desktop 中运行以下命令来测试您的服务器：

* 萨克拉门托的天气怎么样？
* 德克萨斯州的活动天气警报是什么？

<Frame>
  <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/current-weather.png?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=0f7aa65433b72be5ce3e5c463ca90f3a" width="2780" height="1849" data-path="images/current-weather.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/model-context-protocol/PuNtBVMoBLtj46Oz/images/weather-alerts.png?fit=max&auto=format&n=PuNtBVMoBLtj46Oz&q=85&s=7377055662d8860b9834a60e612cae9d" width="2809" height="1850" data-path="images/weather-alerts.png" />
</Frame>

<Note>
  由于这是美国国家气象局，因此查询仅适用于美国位置。
</Note>

## 背后的工作原理

当您提出问题时：

1. 客户端将您的问题发送给 Claude
2. Claude 分析可用工具并决定使用哪些工具
3. 客户端通过 MCP 服务器执行所选工具
4. 结果返回给 Claude
5. Claude 形成自然语言响应
6. 响应显示给您！

## 故障排除

<AccordionGroup>
  <Accordion title="Claude for Desktop 集成问题">
    **从 Claude for Desktop 获取日志**

    与 MCP 相关的 Claude.app 日志记录写入 `~/Library/Logs/Claude` 中的日志文件：

    * `mcp.log` 将包含有关 MCP 连接和连接失败的一般日志记录。
    * 名为 `mcp-server-SERVERNAME.log` 的文件将包含来自命名服务器的错误（stderr）日志记录。

    您可以运行以下命令以列出最近的日志并跟随任何新日志：

    ```bash theme={null}
    # 检查 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

    **这些都不起作用。我该怎么办？**

    请参阅我们的[调试指南](/docs/tools/debugging)以获取更好的调试工具和更详细的指导。
  </Accordion>

  <Accordion title="天气 API 问题">
    **错误：无法检索网格点数据**

    这通常意味着：

    1. 坐标在美国之外
    2. NWS API 有问题
    3. 您被速率限制

    修复：

    * 验证您使用的是美国坐标
    * 在请求之间添加小的延迟
    * 检查 NWS API 状态页面

    **错误：没有 \[STATE] 的活动警报**

    这不是错误 - 这只是意味着该州目前没有天气警报。尝试不同的州或在严重天气期间检查。
  </Accordion>
</AccordionGroup>

<Note>
  有关更高级的故障排除，请查看我们的[调试 MCP](/docs/tools/debugging)指南
</Note>

## 下一步

<CardGroup cols={2}>
  <Card title="构建客户端" icon="outlet" href="/quickstart/client">
    了解如何构建自己的 MCP 客户端以连接到您的服务器
  </Card>

  <Card title="示例服务器" icon="grid" href="/examples">
    查看我们的官方 MCP 服务器和实现的画廊
  </Card>

  <Card title="调试指南" icon="bug" href="/docs/tools/debugging">
    了解如何有效调试 MCP 服务器和集成
  </Card>

  <Card title="使用 LLM 构建 MCP" icon="comments" href="/building-mcp-with-llms">
    了解如何使用 LLM（如 Claude）加速您的 MCP 开发
  </Card>
</CardGroup>
