diff --git a/content/docs/(get-started)/quick-start/server-developers.mdx b/content/docs/(get-started)/quick-start/server-developers.mdx
index 4d993a0..f2db7e2 100644
--- a/content/docs/(get-started)/quick-start/server-developers.mdx
+++ b/content/docs/(get-started)/quick-start/server-developers.mdx
@@ -1,114 +1,1794 @@
----
-title: 服务器开发者
-description: 快速开始 - 服务器开发者
----
+# 针对服务端开发人员
-开始构建自己的服务器,以便在Claude中用于Desktop和其他客户端。
+> 开始构建自己的服务器,以便在Claude中用于Desktop和其他客户端
在本教程中,我们将构建一个简单的MCP天气服务器,并将其连接到主机Claude for Desktop。我们将从基本设置开始,然后进行更复杂的用例。
-## 我们将要干什么
+### 我们将要干什么
+
许多LLM(包括Claude)目前无法获取预报和恶劣天气警报。让我们用MCP解决这个问题。
-我们将构建一个server,该server提供两个工具:get-alerts and get-forecast。然后,我们将服务器连接到MCP主机(在本例中使用Claude for Desktop):
+我们将构建一个server,该server提供两个工具: `get-alerts` and `get-forecast`。然后,我们将服务器连接到MCP主机(在本例中使用Claude for Desktop):
+
+

+

-服务可以连接任何客户端。为了简单起见,我们在这里选择了Claude作为桌面,但我们也有关于[建立自己的client](https://mcp.thinkinai.xyz/docs/quick-start/client-developers)建立自己的client的指南,以及[这里的其他客户列表](https://mcp.thinkinai.xyz/docs/example-clients)。
+
+ 服务可以连接任何客户端。为了简单起见,我们在这里选择了Claude作为桌面,但我们也有关于[建立自己的client](https://mcp.thinkinai.xyz/docs/quick-start/client-developers) 以及 [这里的其他客户列表](https://modelcontextprotocol.io/clients).
+
+
+ 由于服务器是本地运行的,MCP目前只支持桌面主机。远程主机正在积极开发中。
+
-```
-为什么选择Claude for DeskTop而不是Claude.ai?
-由于服务器是本地运行的,MCP目前只支持桌面主机。远程主机正在积极开发中。
-```
+### MCP核心概念
-## MCP核心概念
MCP服务器可以提供三种主要功能:
- 1. **Resources**:客户端可以读取的类文件数据(如API响应或文件内容)
- 2. **Tools**:LLM可以调用的函数(经用户批准)
- 3. **Prompts**:帮助用户完成特定任务的预先编写的模板
+
+1. **Resources**: 客户端可以读取的类文件数据(如API响应或文件内容)
+2. **Tools**: LLM可以调用的函数(经用户批准)
+3. **Prompts**: 帮助用户完成特定任务的预先编写的模板
+
本教程将主要关注工具。
-### 基于Java
-这是一个基于Spring AI MCP自动配置和引导启动器的快速入门演示。要了解如何手动创建同步和异步MCP服务器,请参阅[Java SDK服务器](https://modelcontextprotocol.io/sdk/java/mcp-server)文档。
-让我们开始构建一个天气服务!
- ● [你可以在这里找到我们将要构建的完整代码](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-stdio-server)【MCP官方代码,支持查询美国天气情况】。
- ● [这里的代码也可以](https://github.com/weishuai8888/spring-ai-examples)【fork官方代码后调整了逻辑,支持查询全世界的天气情况】
-有关更多信息,请参阅[MCP Server Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html)参考文档。有关手动MCP服务器实现,请参阅[MCP Server Java SDK文档](https://modelcontextprotocol.io/sdk/java/mcp-server)。
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+
+
+
+ 让我们开始构建我们的天气服务器吧!【你可以在这里找到我们将要构建的完整代码。](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-python)
-#### 系统要求
-~
- ● 已安装Java 17或更高版本
- ● [Spring Boot 3.3.x](https://docs.spring.io/spring-boot/installing.html) 或更高版本
+ ### 预备知识
-#### 设置你的环境变量
-使用 [Spring Initizer](https://start.spring.io) 启动项目。
-你需要添加以下的依赖项:
+ 本快速入门假定您熟悉:
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+ * Python
+ * LLMs like Claude
-
-
- ```xml
-
-
- org.springframework.ai
- spring-ai-starter-mcp-server
-
-
-
- org.springframework
- spring-web
-
-
+ ### 系统要求
+
+ * Python 3.10 or higher installed.
+ * You must use the Python MCP SDK 1.2.0 or higher.
+
+ ### 设置你的环境
+
+ 首先,让我们安装uv并设置我们的Python项目和环境:
+
+
+ ```bash MacOS/Linux
+ curl -LsSf https://astral.sh/uv/install.sh | sh
+ ```
+
+ ```powershell Windows
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
+ ```
+
+
+ 确保之后重新启动终端,以确保收到uv命令。
+
+ 现在,让我们创建并设置我们的项目:
+
+
+ ```bash MacOS/Linux
+ # 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]" httpx
+
+ # Create our server file
+ touch weather.py
+ ```
+
+ ```powershell Windows
+ # 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] httpx
+
+ # Create our server file
+ new-item weather.py
+ ```
+
+
+ 现在,让我们开始构建您的服务器。
+
+ ## 构建您的服务
+
+ ### 导入包并设置实例
+
+ 将这些添加到您的顶部 `weather.py`:
+
+ ```python
+ from typing import Any
+ import httpx
+ from mcp.server.fastmcp import FastMCP
+
+ # Initialize FastMCP server
+ mcp = FastMCP("weather")
+
+ # Constants
+ NWS_API_BASE = "https://api.weather.gov"
+ USER_AGENT = "weather-app/1.0"
```
-
-
- ```xml
- dependencies {
- implementation platform("org.springframework.ai:spring-ai-starter-mcp-server")
- implementation platform("org.springframework:spring-web")
+
+ FastMCP类使用Python类型提示和文档字符串自动生成工具定义,使创建和维护MCP工具变得容易。
+
+ ### 帮助函数
+
+ 接下来,让我们添加我们的助手函数,用于查询和格式化来自美国国家气象局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 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:
+ """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__":
+ # Initialize and run the server
+ mcp.run(transport='stdio')
```
+
+ 您的服务器已完成!运行`uv Run weather.py `以确认一切正常。
+
+ 现在让我们从现有的MCP主机Claude for Desktop测试您的服务器。
+
+ ## 使用Claude for Desktop测试您的服务器
+
+
+ Claude for Desktop尚未在Linux上可用。Linux用户可以继续 [建立客户](https://mcp.thinkinai.xyz/docs/quick-start/client-developers) 构建连接到我们刚刚构建的服务器的MCP客户端的教程。
+
+
+ 首先,确保您安装了Claude for Desktop。[您可以安装最新版本](https://claude.ai/download) 如果你已经有了Claude for Desktop, **确保它已更新到最新版本。**
+
+ 我们需要为您想要使用的任何MCP服务器配置Claude for Desktop。为此,请在以下位置打开Claude for Desktop App配置`~/Library/Application Support/Claude/claude_desktop_config.json` 在文本编辑器中。如果文件不存在,请确保创建该文件。
+
+ 例如,如果你有[VS Code](https://code.visualstudio.com/) 安装:
+
+
+
+ ```bash
+ code ~/Library/Application\ Support/Claude/claude_desktop_config.json
+ ```
+
+
+
+ ```powershell
+ code $env:AppData\Claude\claude_desktop_config.json
+ ```
+
+
+
+ 然后,您将在“mcpServers”键中添加服务器。如果至少有一台服务器配置正确,MCP UI元素将仅显示在Claude for Desktop中。
+ 在这种情况下,我们将添加单个天气服务器,如下所示:
+
+
+
+ ```json Python
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "uv",
+ "args": [
+ "--directory",
+ "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
+ "run",
+ "weather.py"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+ ```json Python
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "uv",
+ "args": [
+ "--directory",
+ "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather",
+ "run",
+ "weather.py"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+
+ 您可能需要将完整路径放在 `uv` 可执行于 `command` 领域. 你可以通过运行来获得这个 `which uv` 在 MacOS/Linux or `where uv` 在 Windows.
+
+
+
+ 确保传入服务器的绝对路径。
+
+
+ 告诉 Claude for Desktop:
+
+ 1. MCP服务器叫做 "weather"
+ 2. 通过运行来启动它 `uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py`
+
+ 保存文件,然后重新启动 **Claude for Desktop**.
-
-然后通过设置应用程序属性来配置应用程序
-
-
- ```yaml
- logging:
- pattern:
- console:
- spring:
- main:
- banner-mode: off
+
+ 让我们开始构建我们的天气服务器吧! [你可以在这里找到我们将要构建的完整代码。](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-typescript)
+
+ ### 预备知识
+
+ 本快速入门假定您熟悉:
+
+ * TypeScript
+ * LLMs like Claude
+
+ ### 系统要求
+
+ 对于TypeScript,请确保您安装了最新版本的Node。
+
+ ### 设置你的环境
+
+ 首先,让我们安装Node.js和npm,如果你还没有的话。您可以从以下网址下载它们 [nodejs.org](https://nodejs.org/).
+ 验证您的 Node.js 安装:
+
+ ```bash
+ node --version
+ npm --version
+ ```
+
+ 对于本教程,您需要Node.js版本16或更高版本。
+ 、
+ 现在,让我们创建并设置我们的项目:
+
+
+ ```bash MacOS/Linux
+ # Create a new directory for our project
+ mkdir weather
+ cd weather
+
+ # Initialize a new npm project
+ npm init -y
+
+ # Install dependencies
+ npm install @modelcontextprotocol/sdk zod
+ npm install -D @types/node typescript
+
+ # Create our files
+ mkdir src
+ touch src/index.ts
+ ```
+
+ ```powershell Windows
+ # Create a new directory for our project
+ md weather
+ cd weather
+
+ # Initialize a new npm project
+ npm init -y
+
+ # Install dependencies
+ npm install @modelcontextprotocol/sdk zod
+ npm install -D @types/node typescript
+
+ # Create our files
+ md src
+ new-item src\index.ts
+ ```
+
+
+ Update your package.json to add type: "module" and a build script:
+
+ ```json package.json
+ {
+ "type": "module",
+ "bin": {
+ "weather": "./build/index.js"
+ },
+ "scripts": {
+ "build": "tsc && chmod 755 build/index.js"
+ },
+ "files": [
+ "build"
+ ],
+ }
```
+
+ Create a `tsconfig.json` in the root of your project:
+
+ ```json 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`:
+
+ ```typescript
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+ import { z } from "zod";
+
+ const NWS_API_BASE = "https://api.weather.gov";
+ const USER_AGENT = "weather-app/1.0";
+
+ // Create server instance
+ const server = new McpServer({
+ name: "weather",
+ version: "1.0.0",
+ capabilities: {
+ resources: {},
+ tools: {},
+ },
+ });
+ ```
+
+ ### 帮助函数
+
+ 接下来,让我们添加我们的助手函数,用于查询和格式化来自美国国家气象局API的数据:
+
+ ```typescript
+ // Helper function for making NWS API requests
+ async function makeNWSRequest(url: string): Promise {
+ const headers = {
+ "User-Agent": USER_AGENT,
+ Accept: "application/geo+json",
+ };
+
+ try {
+ const response = await fetch(url, { headers });
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ 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;
+ };
+ }
+
+ // Format alert data
+ 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[];
+ };
+ }
+ ```
+
+ ### 执行工具
+
+ 工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它:
+
+ ```typescript
+ // Register weather tools
+ server.tool(
+ "get-alerts",
+ "Get weather alerts for a state",
+ {
+ state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"),
+ },
+ async ({ state }) => {
+ const stateCode = state.toUpperCase();
+ const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
+ const alertsData = await makeNWSRequest(alertsUrl);
+
+ if (!alertsData) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: "Failed to retrieve alerts data",
+ },
+ ],
+ };
+ }
+
+ const features = alertsData.features || [];
+ if (features.length === 0) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `No active alerts for ${stateCode}`,
+ },
+ ],
+ };
+ }
+
+ const formattedAlerts = features.map(formatAlert);
+ const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: alertsText,
+ },
+ ],
+ };
+ },
+ );
+
+ server.tool(
+ "get-forecast",
+ "Get weather forecast for a location",
+ {
+ latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
+ longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
+ },
+ async ({ latitude, longitude }) => {
+ // Get grid point data
+ const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
+ const pointsData = await makeNWSRequest(pointsUrl);
+
+ if (!pointsData) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
+ },
+ ],
+ };
+ }
+
+ const forecastUrl = pointsData.properties?.forecast;
+ if (!forecastUrl) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: "Failed to get forecast URL from grid point data",
+ },
+ ],
+ };
+ }
+
+ // Get forecast data
+ const forecastData = await makeNWSRequest(forecastUrl);
+ if (!forecastData) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: "Failed to retrieve forecast data",
+ },
+ ],
+ };
+ }
+
+ const periods = forecastData.properties?.periods || [];
+ if (periods.length === 0) {
+ return {
+ content: [
+ {
+ type: "text",
+ text: "No forecast periods available",
+ },
+ ],
+ };
+ }
+
+ // Format forecast periods
+ 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 = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: forecastText,
+ },
+ ],
+ };
+ },
+ );
+ ```
+
+ ### 运行服务
+
+ 最后,实现运行服务器的主要功能:
+
+ ```typescript
+ 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`来构建你的服务器!这是让服务器连接的一个非常重要的步骤。
+
+ 现在让我们从现有的MCP主机Claude for Desktop测试您的服务器。
+
+ ## 使用Claude for Desktop测试您的服务器
+
+
+ Claude for Desktop尚未在Linux上可用。Linux用户可以继续 [构建一个客户端](https://mcp.thinkinai.xyz/docs/quick-start/client-developers) 构建连接到我们刚刚构建的服务器的MCP客户端的教程。
+
+
+ 首先,确保您安装了Claude for Desktop。 [您可以安装最新版本在这里。](https://claude.ai/download) 如果你已经有了Claude for Desktop, **确保它已更新到最新版本。**
+
+ 我们需要为您想要使用的任何MCP服务器配置Claude for Desktop。为此,请在以下位置打开Claude for Desktop App配置 `~/Library/Application Support/Claude/claude_desktop_config.json` 在文本编辑器中。如果文件不存在,请确保创建该文件。
+
+ 例如,如果你有安装 [VS Code](https://code.visualstudio.com/) :
+
+
+
+ ```bash
+ code ~/Library/Application\ Support/Claude/claude_desktop_config.json
+ ```
+
+
+
+ ```powershell
+ code $env:AppData\Claude\claude_desktop_config.json
+ ```
+
+
+
+ 然后,您将在“mcpServers”键中添加服务器。如果至少有一台服务器配置正确,MCP UI元素将仅显示在Claude for Desktop中。
+
+ 在这种情况下,我们将添加单个天气服务器,如下所示:
+
+
+
+
+ ```json Node
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "node",
+ "args": [
+ "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+
+
+ ```json Node
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "node",
+ "args": [
+ "C:\\PATH\\TO\\PARENT\\FOLDER\\weather\\build\\index.js"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+
+ 告诉 Claude for Desktop:
+
+ 1. 这个 MCP server 称为 "weather"
+ 2. 通过运行启动它 `node /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js`
+
+ 保存文件,然后重新启动 **Claude for Desktop**.
-
+
+
+
+ 这是一个基于Spring AI MCP自动配置和引导启动器的快速入门演示。
+ 要了解如何手动创建同步和异步MCP服务器,请参阅 [Java SDK Server](https://modelcontextprotocol.io/sdk/java/mcp-server) 说明.
+
+
+ 让我们开始构建我们的天气服务器吧!
+ [你可以在这里找到我们将要构建的完整代码。](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-stdio-server)
+
+ 有关更多信息,请参阅 [MCP Server Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html) 参考文件。
+ 有关手动MCP服务器实施,请参阅 [MCP Server Java SDK documentation](https://modelcontextprotocol.io/sdk/java/mcp-server).
+
+ ### 系统要求
+
+ * 安装Java 17 or 更高版本.
+ * [Spring Boot 3.3.x](https://docs.spring.io/spring-boot/installing.html) 或更高版本
+
+ ### 设置您的环境
+
+ 使用[Spring Initializer](https://start.spring.io/) 启动项目。
+
+ 您需要添加以下依赖项:
+
+
+
+ ```xml
+
+
+ org.springframework.ai
+ spring-ai-starter-mcp-server
+
+
+
+ org.springframework
+ spring-web
+
+
+ ```
+
+
+
+ ```groovy
+ dependencies {
+ implementation platform("org.springframework.ai:spring-ai-starter-mcp-server")
+ implementation platform("org.springframework:spring-web")
+ }
+ ```
+
+
+
+ 然后通过设置应用程序属性来配置应用程序:
+
+
+ ```bash application.properties
+ spring.main.bannerMode=off
+ logging.pattern.console=
+ ```
+
+ ```yaml application.yml
+ logging:
+ pattern:
+ console:
+ spring:
+ main:
+ banner-mode: off
+ ```
+
+
+ 这个 [服务器配置属性](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_configuration_properties) 记录所有可用的属性。
+
+ 现在,让我们开始构建您的服务器。
+
+ ## 构建您的服务
+
+ ### 天气服务
+
+ 让我们实现一个 [WeatherService.java](https://github.com/spring-projects/spring-ai-examples/blob/main/model-context-protocol/weather/starter-stdio-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java) REST客户端来查询来自美国国家气象局API的数据:
+
+ ```java
+ @Service
+ public class WeatherService {
+
+ private final RestClient restClient;
+
+ public WeatherService() {
+ 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 = "Get weather forecast for a specific latitude/longitude")
+ public String getWeatherForecastByLocation(
+ double latitude, // Latitude coordinate
+ double longitude // Longitude coordinate
+ ) {
+ // Returns detailed forecast including:
+ // - Temperature and unit
+ // - Wind speed and direction
+ // - Detailed forecast description
+ }
+
+ @Tool(description = "Get weather alerts for a US state")
+ public String getAlerts(
+ @ToolParam(description = "Two-letter US state code (e.g. CA, NY)" String state
+ ) {
+ // Returns active alerts including:
+ // - Event type
+ // - Affected area
+ // - Severity
+ // - Description
+ // - Safety instructions
+ }
+
+ // ......
+ }
+ ```
+
+ 这个`@Service` 在应用程序上下文中自动注册服务的注释。
+
+ Spring AI的“@Tool”注释,使创建和维护MCP工具变得容易。
+
+ 自动配置将自动向MCP服务器注册这些工具。
+
+ ### 创建你的Boot应用
+
+ ```java
+ @SpringBootApplication
+ public class McpServerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(McpServerApplication.class, args);
+ }
+
+ @Bean
+ public ToolCallbackProvider weatherTools(WeatherService weatherService) {
+ return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
+ }
+ }
+ ```
+
+ 使用“MethodToolcallback Provider”实用程序将“@Tools”转换为MCP服务器使用的可操作回调。
+
+ ### 运行服务
+
+ 最后,让我们构建服务器:
+
+ ```bash
+ ./mvnw clean install
+ ```
+
+ 这将在“target”文件夹中生成一个“mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar”文件。
+
+ 现在让我们从现有的MCP主机Claude for Desktop测试您的服务器。
+
+ ## 使用Claude for Desktop测试您的服务器
+
+
+ Claude for Desktop尚未在Linux上可用。
+
+
+ 首先,确保您安装了Claude for Desktop。
+ [您可以在此处安装最新版本。](https://claude.ai/download) 如果您已经拥有Claude for Desktop,**请确保它已更新到最新版本**
+
+ 我们需要为您想要使用的任何MCP服务器配置Claude for Desktop。
+ 为此,请在文本编辑器中打开位于`~/Library/ApplicationSupport/Claude/Claude_Desktop_config.json`的Claude for Desktop App配置。
+ 如果文件不存在,请确保创建该文件。
+
+ 例如,如果你已经安装[VS Code](https://code.visualstudio.com/):
+
+
+
+ ```bash
+ code ~/Library/Application\ Support/Claude/claude_desktop_config.json
+ ```
+
+
+
+ ```powershell
+ code $env:AppData\Claude\claude_desktop_config.json
+ ```
+
+
+
+ 然后,您将在`mcpServers`键中添加服务器。
+ 如果至少有一台服务器配置正确,MCP UI元素将仅显示在Claude for Desktop中。
+ 在这种情况下,我们将添加单个天气服务器,如下所示:
+
+
+
+
+ ```json java
+ {
+ "mcpServers": {
+ "spring-ai-mcp-weather": {
+ "command": "java",
+ "args": [
+ "-Dspring.ai.mcp.server.stdio=true",
+ "-jar",
+ "/ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+ ```json java
+ {
+ "mcpServers": {
+ "spring-ai-mcp-weather": {
+ "command": "java",
+ "args": [
+ "-Dspring.ai.mcp.server.transport=STDIO",
+ "-jar",
+ "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather\\mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+
+ 确保传入服务器的绝对路径。
+
+
+ 此消息告诉Claude for Desktop:
+ 1.有一个名为“我的天气服务器”的MCP服务器
+ 2.通过运行`java-jar/AABSOLUTE/PATH/To/PARENT/FOLDER/mcp-weather-stdio-server--0.1-SNAPSHOT.jar来启动它`
+ 保存文件,然后重新启动**Claude for Desktop**。
+
+ ## 使用Java客户端测试您的服务器
+
+ ### 手动创建MCP客户端
+
+ 使用`McpClient`连接到服务器:
+
+
+ ```java
+ var stdioParams = ServerParameters.builder("java")
+ .args("-jar", "/ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar")
+ .build();
+
+ var stdioTransport = new StdioClientTransport(stdioParams);
+
+ var mcpClient = McpClient.sync(stdioTransport).build();
+
+ mcpClient.initialize();
+
+ ListToolsResult toolsList = mcpClient.listTools();
+
+ CallToolResult weather = mcpClient.callTool(
+ new CallToolRequest("getWeatherForecastByLocation",
+ Map.of("latitude", "47.6062", "longitude", "-122.3321")));
+
+ CallToolResult alert = mcpClient.callTool(
+ new CallToolRequest("getAlerts", Map.of("state", "NY")));
+
+ mcpClient.closeGracefully();
+ ```
+
+ ### 使用MCP客户端引导启动器
+
+ 使用`spring-ai-starter-mcp-client`依赖项创建一个新的引导启动器应用程序:
+
+ ```xml
+
+ org.springframework.ai
+ spring-ai-starter-mcp-client
+
+ ```
+
+ 并将`spring.ai.mcp.client.sdio.servers配置`属性设置为指向您的`claude_desktop_config.json`。
+ 您可以重新使用现有的Anthropic Desktop配置:
+
```properties
- logging.pattern.console=
- spring.main.banner-mode=off
+ spring.ai.mcp.client.stdio.servers-configuration=file:PATH/TO/claude_desktop_config.json
+ ```
+
+ 当您启动客户端应用程序时,自动配置将从claude\_desktop\_config.json自动创建MCP客户端。
+
+ 有关更多信息,请参阅[MCP客户端启动程序](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-client-docs.html)参考文件。
+
+ ##更多Java MCP服务器示例
+
+ 这个[starter-webflux-server](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-webflux-server) 演示如何使用SSE传输创建MCP服务器。
+ 它展示了如何使用Spring Boot的自动配置功能定义和注册MCP工具、资源和提示。
+
+
+
+ 让我们开始构建我们的天气服务器吧
+
+ ### 必备知识
+
+ 本快速入门假定您熟悉:
+
+ * Kotlin
+ * LLMs like Claude
+
+ ### 系统要求
+
+ * Java 17 or higher installed.
+
+ ### 设置你的环境
+
+ 首先,让我们安装`java`和`gradle`(如果还没有的话)。
+
+ 您可以从[Oracle JDK官方网站]下载`java`(https://www.oracle.com/java/technologies/downloads/).
+
+ 验证您的“java”安装:
+
+ ```bash
+ java --version
+ ```
+
+ 现在,让我们创建并设置您的项目:
+
+
+ ```bash MacOS/Linux
+ # Create a new directory for our project
+ mkdir weather
+ cd weather
+
+ # Initialize a new kotlin project
+ gradle init
+ ```
+
+ ```powershell Windows
+ # Create a new directory for our project
+ md weather
+ cd weather
+
+ # Initialize a new kotlin project
+ gradle init
+ ```
+
+
+ 运行`gradle init`后,您将看到创建项目的选项。
+
+ 选择**Application**作为项目类型,**Kotlin**作为编程语言,**Java17**作为Java版本。
+
+ 或者,您可以使用[IntelliJ IDEA项目向导]创建Kotlin应用程序(https://kotlinlang.org/docs/jvm-get-started.html).
+
+
+ ```kotlin 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")
+ }
+ ```
+
+ ```groovy build.gradle
+ def mcpVersion = '0.3.0'
+ def slf4jVersion = '2.0.9'
+ def 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"
+ }
+ ```
+
+
+ 此外,将以下插件添加到您的构建脚本中:
+
+
+ ```kotlin build.gradle.kts
+ plugins {
+ kotlin("plugin.serialization") version "your_version_of_kotlin"
+ id("com.github.johnrengelman.shadow") version "8.1.1"
+ }
+ ```
+
+ ```groovy build.gradle
+ plugins {
+ id 'org.jetbrains.kotlin.plugin.serialization' version 'your_version_of_kotlin'
+ id 'com.github.johnrengelman.shadow' version '8.1.1'
+ }
+ ```
+
+
+ 现在,让我们开始构建您的服务器。
+
+ ## 构建您的服务器
+
+ ### 设置实例
+
+ 添加服务器初始化功能:
+
+ ```kotlin
+ // Main function to run the MCP server
+ fun `run mcp server`() {
+ // Create the MCP Server instance with a basic implementation
+ val server = Server(
+ Implementation(
+ name = "weather", // Tool name is "weather"
+ version = "1.0.0" // Version of the implementation
+ ),
+ ServerOptions(
+ capabilities = ServerCapabilities(tools = ServerCapabilities.Tools(listChanged = true))
+ )
+ )
+
+ // Create a transport using standard IO for server communication
+ val transport = StdioServerTransport(
+ System.`in`.asInput(),
+ System.out.asSink().buffered()
+ )
+
+ runBlocking {
+ server.connect(transport)
+ val done = Job()
+ server.onClose {
+ done.complete()
+ }
+ done.join()
+ }
+ }
+ ```
+
+ ### 天气API助手函数
+
+ 接下来,让我们添加用于查询和转换来自美国国家气象局API的响应的函数和数据类:
+
+ ```kotlin
+ // Extension function to fetch forecast information for given latitude and longitude
+ suspend fun HttpClient.getForecast(latitude: Double, longitude: Double): List {
+ val points = this.get("/points/$latitude,$longitude").body()
+ val forecast = this.get(points.properties.forecast).body()
+ return forecast.properties.periods.map { period ->
+ """
+ ${period.name}:
+ Temperature: ${period.temperature} ${period.temperatureUnit}
+ Wind: ${period.windSpeed} ${period.windDirection}
+ Forecast: ${period.detailedForecast}
+ """.trimIndent()
+ }
+ }
+
+ // Extension function to fetch weather alerts for a given state
+ suspend fun HttpClient.getAlerts(state: String): List {
+ val alerts = this.get("/alerts/active/area/$state").body()
+ 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()
+ }
+ }
+
+ @Serializable
+ data class Points(
+ val properties: Properties
+ ) {
+ @Serializable
+ data class Properties(val forecast: String)
+ }
+
+ @Serializable
+ data class Forecast(
+ val properties: Properties
+ ) {
+ @Serializable
+ data class Properties(val periods: List)
+
+ @Serializable
+ data class Period(
+ val number: Int, val name: String, val startTime: String, val endTime: String,
+ val isDaytime: Boolean, val temperature: Int, val temperatureUnit: String,
+ val temperatureTrend: String, val probabilityOfPrecipitation: JsonObject,
+ val windSpeed: String, val windDirection: String,
+ val shortForecast: String, val detailedForecast: String,
+ )
+ }
+
+ @Serializable
+ data class Alert(
+ val features: List
+ ) {
+ @Serializable
+ data class Feature(
+ val properties: Properties
+ )
+
+ @Serializable
+ data class Properties(
+ val event: String, val areaDesc: String, val severity: String,
+ val description: String, val instruction: String?,
+ )
+ }
+ ```
+
+ ### 执行工具
+
+ 工具执行处理程序负责实际执行每个工具的逻辑。让我们添加它:
+
+
+ ```kotlin
+ // Create an HTTP client with a default request configuration and JSON content negotiation
+ 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 content negotiation plugin for JSON serialization/deserialization
+ install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) }
+ }
+
+ // Register a tool to fetch weather alerts by state
+ server.addTool(
+ name = "get_alerts",
+ description = """
+ Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)
+ """.trimIndent(),
+ inputSchema = Tool.Input(
+ properties = buildJsonObject {
+ putJsonObject("state") {
+ put("type", "string")
+ put("description", "Two-letter US state code (e.g. CA, NY)")
+ }
+ },
+ required = listOf("state")
+ )
+ ) { request ->
+ val state = request.arguments["state"]?.jsonPrimitive?.content
+ if (state == null) {
+ return@addTool CallToolResult(
+ content = listOf(TextContent("The 'state' parameter is required."))
+ )
+ }
+
+ val alerts = httpClient.getAlerts(state)
+
+ CallToolResult(content = alerts.map { TextContent(it) })
+ }
+
+ // Register a tool to fetch weather forecast by latitude and longitude
+ server.addTool(
+ name = "get_forecast",
+ description = """
+ Get weather forecast for a specific latitude/longitude
+ """.trimIndent(),
+ 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("The 'latitude' and 'longitude' parameters are required."))
+ )
+ }
+
+ val forecast = httpClient.getForecast(latitude, longitude)
+
+ CallToolResult(content = forecast.map { TextContent(it) })
+ }
+ ```
+
+ ### 运行服务
+
+ 最后,实现运行服务器的主要功能:
+
+ ```kotlin
+ fun main() = `run mcp server`()
+ ```
+
+ 一定要跑`/gradlew build`来构建你的服务器。这是让服务器连接的一个非常重要的步骤。
+
+ 现在让我们从现有的MCP主机Claude for Desktop测试您的服务器。
+
+ ## 使用Claude for Desktop测试您的服务器
+
+
+ Claude for Desktop尚未在Linux上可用。Linux用户可以继续学习[构建客户端](https://mcp.thinkinai.xyz/docs/quick-start/client-developers)教程,以构建一个连接到我们刚刚构建的服务器的MCP客户端。
+
+
+ 首先,确保您安装了Claude for Desktop。[您可以安装最新版本在这里。](https://claude.ai/download)如果您已经拥有Claude for Desktop,**请确保它已更新到最新版本**
+
+ 我们需要为您想要使用的任何MCP服务器配置Claude for Desktop。
+ `~/Library/ApplicationSupport/Claude/Claude_Desktop_config.json`的Claude for Desktop App配置。
+
+ 如果文件不存在,请确保创建该文件。
+
+ 例如,如果你有[VS code](https://code.visualstudio.com/)已安装:
+
+
+ ```bash MacOS/Linux
+ code ~/Library/Application\ Support/Claude/claude_desktop_config.json
+ ```
+
+ ```powershell Windows
+ code $env:AppData\Claude\claude_desktop_config.json
+ ```
+
+
+ 然后,您将在`mcpServers`键中添加服务器。
+
+ 如果至少有一台服务器配置正确,MCP UI元素将仅显示在Claude for Desktop中。
+
+ 在这种情况下,我们将添加单个天气服务器,如下所示:
+
+
+ ```json MacOS/Linux
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "java",
+ "args": [
+ "-jar",
+ "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/libs/weather-0.1.0-all.jar"
+ ]
+ }
+ }
+ }
+ ```
+
+ ```json Windows
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "java",
+ "args": [
+ "-jar",
+ "C:\\PATH\\TO\\PARENT\\FOLDER\\weather\\build\\libs\\weather-0.1.0-all.jar"
+ ]
+ }
+ }
+ }
+ ```
+
+
+ 这将告诉Claude for Desktop:
+
+ 1.有一个名为“天气”的MCP服务器
+
+ 2.通过运行`java-jar/AABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/libs/weather-0.1.0-all.jar启动它`
+
+ 保存文件,然后重新启动**Claude for Desktop**。
+
+
+
+ 让我们开始构建我们的天气服务器吧
+
+ ### 必备知识
+
+ 本快速入门假定您熟悉:
+
+ * C#
+ * LLMs like Claude
+ * .NET 8 or higher
+
+ ### 系统要求
+
+ * 安装[.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) 或更高版本。
+
+ ### 配置您的系统环境
+
+ 首先,让我们安装`dotnet`,如果你还没有的话。您可以从[微软官方.NET网站]下载`dotnet`(https://dotnet.microsoft.com/download/). 验证您的`dot`安装:
+
+ ```bash
+ dotnet --version
```
+
+ 现在,让我们创建并设置您的项目:
+
+
+ ```bash MacOS/Linux
+ # Create a new directory for our project
+ mkdir weather
+ cd weather
+ # Initialize a new C# project
+ dotnet new console
+ ```
+
+ ```powershell Windows
+ # Create a new directory for our project
+ mkdir weather
+ cd weather
+ # Initialize a new C# project
+ dotnet new console
+ ```
+
+
+ 运行`dotnetnew console `后,您将看到一个新的C#项目。
+
+ 您可以在您喜欢的IDE中打开项目,例如[Visual Studio](https://visualstudio.microsoft.com/)或[骑手](https://www.jetbrains.com/rider/).
+
+ 或者,您可以使用[Visual Studio项目向导]创建C#应用程序(https://learn.microsoft.com/en-us/visualstudio/get-started/csharp/tutorial-console?view=vs-2022).
+
+ 创建项目后,为模型上下文协议SDK添加NuGet包并托管:
+
+ ```bash
+ # Add the Model Context Protocol SDK NuGet package
+ dotnet add package ModelContextProtocol --prerelease
+ # Add the .NET Hosting NuGet package
+ dotnet add package Microsoft.Extensions.Hosting
+ ```
+
+ 现在,让我们开始构建您的服务器。
+
+ ## 构建您的服务
+
+ 在项目中打开`Program.cs`文件,并用以下代码替换其内容:
+
+ ```csharp
+ using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.Extensions.Hosting;
+ using ModelContextProtocol;
+ using System.Net.Http.Headers;
+
+ var builder = Host.CreateEmptyApplicationBuilder(settings: null);
+
+ builder.Services.AddMcpServer()
+ .WithStdioServerTransport()
+ .WithToolsFromAssembly();
+
+ 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`而不是`CreateDefaultBuilder`。这可确保服务器不会向控制台写入任何其他消息。这仅对使用STDIO传输的服务器是必要的。
+
+
+ 此代码设置了一个基本的控制台应用程序,该应用程序使用模型上下文协议SDK创建具有标准I/O传输的MCP服务器。
+
+ ### 天气API助手函数
+
+ 接下来,使用工具执行处理程序定义一个类,用于查询和转换来自美国国家气象局API的响应:
+
+ ```csharp
+ using ModelContextProtocol.Server;
+ using System.ComponentModel;
+ using System.Net.Http.Json;
+ using System.Text.Json;
+
+ namespace QuickstartWeatherServer.Tools;
+
+ [McpServerToolType]
+ public static class WeatherTools
+ {
+ [McpServerTool, Description("Get weather alerts for a US state.")]
+ public static async Task GetAlerts(
+ HttpClient client,
+ [Description("The US state to get alerts for.")] string state)
+ {
+ var jsonElement = await client.GetFromJsonAsync($"/alerts/active/area/{state}");
+ var alerts = jsonElement.GetProperty("features").EnumerateArray();
+
+ if (!alerts.Any())
+ {
+ return "No active alerts for this state.";
+ }
+
+ 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("Get weather forecast for a location.")]
+ public static async Task GetForecast(
+ HttpClient client,
+ [Description("Latitude of the location.")] double latitude,
+ [Description("Longitude of the location.")] double longitude)
+ {
+ var jsonElement = await client.GetFromJsonAsync($"/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()}
+ """));
+ }
+ }
+ ```
+
+ ### 运行服务
+
+ 最后,使用以下命令运行服务器:
+
+ ```bash
+ dotnet run
+ ```
+
+ 这将启动服务器并监听标准输入/输出上的传入请求。
+
+ ## 使用Claude for Desktop测试您的服务器
+
+
+ Claude for Desktop尚未在Linux上可用。Linux用户可以继续学习[构建客户端](https://mcp.thinkinai.xyz/docs/quick-start/client-developers)教程,以构建一个连接到我们刚刚构建的服务器的MCP客户端。
+
+
+ 首先,确保您安装了Claude for Desktop。[您可以安装最新版本 在这里。](https://claude.ai/download)如果您已经拥有Claude for Desktop,**请确保它已更新到最新版本**
+
+ 我们需要为您想要使用的任何MCP服务器配置Claude for Desktop。为此,请在文本编辑器中打开位于`~/Library/ApplicationSupport/Claude/Claude_Desktop_config.json`的Claude for Desktop App配置。如果文件不存在,请确保创建该文件。
+
+ 例如,如果你有[VS代码](https://code.visualstudio.com/)已安装:
+
+
+
+
+ ```bash
+ code ~/Library/Application\ Support/Claude/claude_desktop_config.json
+ ```
+
+
+
+ ```powershell
+ code $env:AppData\Claude\claude_desktop_config.json
+ ```
+
+
+
+ 然后,您将在`mcpServers`键中添加服务器。如果至少有一台服务器配置正确,MCP UI元素将仅显示在Claude for Desktop中。
+ 在这种情况下,我们将添加单个天气服务器,如下所示:
+
+
+
+ ```json
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "dotnet",
+ "args": [
+ "run",
+ "--project",
+ "/ABSOLUTE/PATH/TO/PROJECT",
+ "--no-build"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+ ```json
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "dotnet",
+ "args": [
+ "run",
+ "--project",
+ "C:\\ABSOLUTE\\PATH\\TO\\PROJECT",
+ "--no-build"
+ ]
+ }
+ }
+ }
+ ```
+
+
+
+ 这将告诉 Claude for Desktop:
+
+ 1.有一个名为“天气”的MCP服务器
+
+ 2.通过运行`dotnetrun/AABSOLUTE/PATH/TO/PROJECT启动它` ,保存文件,然后重新启动**Claude for Desktop**。
-[服务器配置属性](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_configuration_properties)记录了所有可用的属性。现在,让我们开始构建您的服务器。
+### 使用命令进行测试
+
+让我们确保Claude for Desktop正在使用我们在`天气`服务器中公开的两个工具。你可以通过寻找锤子来做到这一点
icon:
+
+
+
+
+点击锤子图标后,您应该看到列出了两个工具:
+
+
+
+如果您的服务器没有被Claude for Desktop接收,请继续进行[故障排除]部分以获取调试提示。
+
+如果锤子图标已显示,您现在可以在Claude for Desktop中运行以下命令来测试您的服务器:
+
+* 萨克拉门托的天气怎么样?
+
+* 德克萨斯州的活跃天气警报是什么?
+
+
+
+
+
+
+
+
+ 由于这是美国国家气象局,因此查询仅适用于美国各地。
+
+
+## hood下面发生了什么
+
+当你问一个问题时:
+
+1.客户将您的问题发送给Claude
+
+2.Claude分析可用的工具并决定使用哪一个
+
+3.客户端通过MCP服务器执行所选工具
+
+4.结果被发送回克劳德
+
+5.克劳德制定了一个自然语言反应
+
+6.响应已显示给您!
+
+
+## 故障排除
+
+
+
+ **从Claude获取桌面日志**
+
+ 与MCP相关的Claude.app日志记录被写入`~/Library/Logs/Claude`中的日志文件:
+
+ *`mcp.log`将包含有关mcp连接和连接失败的一般日志记录。
+
+ *名为`mcp-server SERVERNAME.log`的文件将包含来自指定服务器的错误(stderr)日志记录。
+
+ 您可以运行以下命令列出最近的日志,并跟踪任何新日志:
+
+ ```bash
+ # Check Claude's logs for errors
+ tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
+ ```
+
+ **服务器未在Claude中显示**
+
+ 1.检查`claude_desktop_config.json `文件语法
+
+ 2.确保项目的路径是绝对的,而不是相对的
+
+ 3.完全重启Claude for Desktop
+
+ **工具调用无声失败**
+
+ 如果克劳德试图使用这些工具,但失败了:
+
+ 1.检查克劳德的日志是否有错误
+
+ 2.验证您的服务器构建和运行没有错误
+
+ 3.尝试重新启动Claude for Desktop
+
+ **这些都不起作用。我该怎么办**
+
+ 请参阅我们的[调试指南](https://mcp.thinkinai.xyz/docs/tutorials/debugging),了解更好的调试工具和更详细的指导。
+
+
+
+ **错误:检索网格点数据失败**
+
+ 这通常意味着:
-# 构建你的服务器
-## 天气服务
+ 1.坐标在美国境外
+ 2.NWS API出现问题
+ 3.你的价格有限
+ 修复:
+ *验证您使用的是美国坐标
+ *在请求之间添加一点延迟
+ *查看NWS API状态页面
+ **错误:\[STATE]没有活动警报**
+ 这不是一个错误,只是意味着该州目前没有天气警报。尝试不同的状态或在恶劣天气下检查。
+
+
+
+ 有关更高级的故障排除,请查看我们的[调试MCP]指南(https://mcp.thinkinai.xyz/docs/tutorials/debugging)
+
+## 下一步行动
+
+
+ 了解如何构建可以连接到服务器的MCP客户端
+
+
+ 查看我们的官方MCP服务器和实现库
+
+
+ 了解如何有效地调试MCP服务器和集成
+
+
+ 学习如何使用像Claude这样的LLM来加速您的MCP开发
+
+
diff --git a/content/docs/(get-started)/quick-start/server-developers.mdx.bak b/content/docs/(get-started)/quick-start/server-developers.mdx.bak
new file mode 100644
index 0000000..2d9291d
--- /dev/null
+++ b/content/docs/(get-started)/quick-start/server-developers.mdx.bak
@@ -0,0 +1,249 @@
+---
+title: 服务器开发者
+description: 快速开始 - 服务器开发者
+---
+
+开始构建自己的服务器,以便在Claude中用于Desktop和其他客户端。
+
+在本教程中,我们将构建一个简单的MCP天气服务器,并将其连接到主机Claude for Desktop。我们将从基本设置开始,然后进行更复杂的用例。
+
+## 我们将要干什么
+许多LLM(包括Claude)目前无法获取预报和恶劣天气警报。让我们用MCP解决这个问题。
+
+我们将构建一个server,该server提供两个工具:get-alerts and get-forecast。然后,我们将服务器连接到MCP主机(在本例中使用Claude for Desktop):
+
+
+
+
+服务可以连接任何客户端。为了简单起见,我们在这里选择了Claude作为桌面,但我们也有关于[建立自己的client](https://mcp.thinkinai.xyz/docs/quick-start/client-developers)建立自己的client的指南,以及[这里的其他客户列表](https://mcp.thinkinai.xyz/docs/example-clients)。
+
+
+```
+为什么选择Claude for DeskTop而不是Claude.ai?
+由于服务器是本地运行的,MCP目前只支持桌面主机。远程主机正在积极开发中。
+```
+
+## MCP核心概念
+MCP服务器可以提供三种主要功能:
+ 1. **Resources**:客户端可以读取的类文件数据(如API响应或文件内容)
+ 2. **Tools**:LLM可以调用的函数(经用户批准)
+ 3. **Prompts**:帮助用户完成特定任务的预先编写的模板
+本教程将主要关注工具。
+
+### 基于Java
+这是一个基于Spring AI MCP自动配置和引导启动器的快速入门演示。要了解如何手动创建同步和异步MCP服务器,请参阅[Java SDK服务器](https://modelcontextprotocol.io/sdk/java/mcp-server)文档。
+
+让我们开始构建一个天气服务【MCP官方代码,支持查询美国天气情况】。
+[这里的代码也可以](https://github.com/weishuai8888/spring-ai-examples)【fork官方代码后调整了逻辑,支持查询全世界的天气情况】
+
+有关更多信息,请参阅[MCP Server Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html)参考文档。有关手动MCP服务器实现,请参阅[MCP Server Java SDK文档](https://modelcontextprotocol.io/sdk/java/mcp-server)。
+
+#### 系统要求
+~
+ ● 已安装Java 17或更高版本
+ ● [Spring Boot 3.3.x](https://docs.spring.io/spring-boot/installing.html) 或更高版本
+
+#### 设置你的环境变量
+使用 [Spring Initizer](https://start.spring.io) 启动项目。
+
+你需要添加以下的依赖项:
+
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+
+
+
+ ```xml
+
+
+ org.springframework.ai
+ spring-ai-starter-mcp-server
+
+
+
+ org.springframework
+ spring-web
+
+
+ ```
+
+
+ ```xml
+ dependencies {
+ implementation platform("org.springframework.ai:spring-ai-starter-mcp-server")
+ implementation platform("org.springframework:spring-web")
+ }
+ ```
+
+
+
+然后通过设置应用程序属性来配置应用程序
+
+
+
+ ```yaml
+ logging:
+ pattern:
+ console:
+ spring:
+ main:
+ banner-mode: off
+ ```
+
+
+ ```properties
+ logging.pattern.console=
+ spring.main.banner-mode=off
+ ```
+
+
+
+[服务器配置属性](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_configuration_properties)记录了所有可用的属性。现在,让我们开始构建您的服务器。
+
+# 构建你的服务器
+## 天气服务
+让我们实现一个WeatherService.java,它使用 REST 客户端从国家气象局 API 查询数据:
+``` java
+@Service
+public class WeatherService {
+
+ private final RestClient restClient;
+
+ public WeatherService() {
+ 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 = "Get weather forecast for a specific latitude/longitude")
+ public String getWeatherForecastByLocation(
+ double latitude, // Latitude coordinate
+ double longitude // Longitude coordinate
+ ) {
+ // Returns detailed forecast including:
+ // - Temperature and unit
+ // - Wind speed and direction
+ // - Detailed forecast description
+ }
+
+ @Tool(description = "Get weather alerts for a US state")
+ public String getAlerts(
+ @ToolParam(description = "Two-letter US state code (e.g. CA, NY)" String state
+ ) {
+ // Returns active alerts including:
+ // - Event type
+ // - Affected area
+ // - Severity
+ // - Description
+ // - Safety instructions
+ }
+
+ // ......
+}
+```
+该@Service注释会自动在应用程序上下文中注册服务。Spring AI@Tool注释使创建和维护 MCP 工具变得容易。
+
+自动配置将自动向 MCP 服务器注册这些工具。
+
+## 创建启动应用程序
+``` java
+@SpringBootApplication
+public class McpServerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(McpServerApplication.class, args);
+ }
+
+ @Bean
+ public ToolCallbackProvider weatherTools(WeatherService weatherService) {
+ return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
+ }
+}
+```
+使用实用MethodToolCallbackProvider程序将其转换@Tools为 MCP 服务器使用的可操作回调。
+
+## 运行服务器
+最后,让我们构建服务器:
+```bash
+./mvnw clean install
+```
+这将在文件夹mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar中生成一个文件target。
+
+现在让我们从现有的 MCP 主机 Claude for Desktop 测试您的服务器。
+
+# 使用 Claude for Desktop 测试你的服务器
+Claude for Desktop 尚未在 Linux 上提供。
+
+首先,请确保您已安装 Claude for Desktop。 [您可以在此处安装最新版本](https://www.anthropic.com/app-unavailable-in-region)。如果您已经安装了 Claude for Desktop,[请确保它已更新到最新版本](https://www.anthropic.com/app-unavailable-in-region)。
+
+我们需要为您想要使用的 MCP 服务器配置 Claude for Desktop。为此,请在~/Library/Application Support/Claude/claude_desktop_config.json文本编辑器中打开您的 Claude for Desktop App 配置。如果该文件不存在,请务必创建。
+
+例如,如果你安装了VS Code:
+
+
+
+ ```shell
+ code ~/Library/Application\ Support/Claude/claude_desktop_config.json
+ ```
+
+
+ ```bash
+ code $env:AppData\Claude\claude_desktop_config.json
+ ```
+
+
+
+然后您将在密钥中添加服务器mcpServers。只有至少一台服务器配置正确,MCP UI 元素才会显示在 Claude for Desktop 中。
+
+在这种情况下,我们将像这样添加单个天气服务器:
+
+
+ ```java
+ {
+ "mcpServers": {
+ "spring-ai-mcp-weather": {
+ "command": "java",
+ "args": [
+ "-Dspring.ai.mcp.server.stdio=true",
+ "-jar",
+ "/ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar"
+ ]
+ }
+ }
+ }
+ ```
+
+
+ ```bash
+ {
+ "mcpServers": {
+ "spring-ai-mcp-weather": {
+ "command": "java",
+ "args": [
+ "-Dspring.ai.mcp.server.transport=STDIO",
+ "-jar",
+ "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather\\mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar"
+ ]
+ }
+ }
+ }
+ ```
+
+
+确保传递了服务器的绝对路径。
+
+这告诉 Claude for Desktop:
+
+1. 有一个名为“my-weather-server”的 MCP 服务器
+2. 通过运行来启动它java -jar /ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar
+
+保存文件并重新启动Claude for Desktop。
+
+
+
+
+
+
+
+
diff --git a/content/docs/concepts/core-architecture.mdx b/content/docs/concepts/core-architecture.mdx
new file mode 100644
index 0000000..af57329
--- /dev/null
+++ b/content/docs/concepts/core-architecture.mdx
@@ -0,0 +1,331 @@
+# 核心架构
+
+> 了解 MCP 如何连接客户端、服务器和 LLM
+
+模型上下文协议 (MCP) 建立在灵活、可扩展的架构上,可实现 LLM 应用程序和集成之间的无缝通信。本文档涵盖核心架构组件和概念。
+
+## 概述
+
+MCP 遵循客户端-服务器架构,其中:
+
+* **主机** 是发起连接的 LLM 应用程序(如 Claude Desktop 或 IDE)
+* **客户端**在主机应用程序内部与服务器保持 1:1 连接
+* **服务器** 向客户提供上下文、工具和提示
+
+
+
+
+## 核心组件
+
+### 协议层
+
+协议层处理消息框架、请求/响应链接和高级通信模式。
+
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+
+
+
+ ```typescript
+ class Protocol {
+ // Handle incoming requests
+ setRequestHandler(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise): void
+
+ // Handle incoming notifications
+ setNotificationHandler(schema: T, handler: (notification: T) => Promise): void
+
+ // Send requests and await responses
+ request(request: Request, schema: T, options?: RequestOptions): Promise
+
+ // Send one-way notifications
+ notification(notification: Notification): Promise
+ }
+ ```
+
+
+
+ ```python
+ class Session(BaseSession[RequestT, NotificationT, ResultT]):
+ async def send_request(
+ self,
+ request: RequestT,
+ result_type: type[Result]
+ ) -> Result:
+ """
+ Send request and wait for response. Raises McpError if response contains error.
+ """
+ # Request handling implementation
+
+ async def send_notification(
+ self,
+ notification: NotificationT
+ ) -> None:
+ """Send one-way notification that doesn't expect response."""
+ # Notification handling implementation
+
+ async def _received_request(
+ self,
+ responder: RequestResponder[ReceiveRequestT, ResultT]
+ ) -> None:
+ """Handle incoming request from other side."""
+ # Request handling implementation
+
+ async def _received_notification(
+ self,
+ notification: ReceiveNotificationT
+ ) -> None:
+ """Handle incoming notification from other side."""
+ # Notification handling implementation
+ ```
+
+
+
+主要课程包括:
+
+- Protocol
+- Client
+- Server
+
+### 传输层
+
+传输层处理客户端和服务器之间的实际通信。MCP 支持多种传输机制:
+
+1. **Stdio 传输**
+ * 使用标准输入/输出进行通信
+ * 适合本地流程
+
+2. **带有 SSE 传输的 HTTP**
+ * 使用服务器发送事件来发送服务器到客户端的消息
+ * HTTP POST 用于客户端到服务器的消息
+
+所有传输均使用 [JSON-RPC](https://www.jsonrpc.org/) 2.0 来交换消息。有关模型上下文协议消息格式的详细信息,请参阅 [规范](/specification/)。
+
+### 消息类型
+
+MCP 有以下主要类型的消息:
+
+1. **请求**期望对方做出回应:
+ ```typescript
+ interface Request {
+ method: string;
+ params?: { ... };
+ }
+ ```
+
+2. **结果**是对请求的成功响应:
+ ```typescript
+ interface Result {
+ [key: string]: unknown;
+ }
+ ```
+
+3. **错误**表示请求失败:
+ ```typescript
+ interface Error {
+ code: number;
+ message: string;
+ data?: unknown;
+ }
+ ```
+
+4. **通知**是单向消息,不期望得到响应:
+ ```typescript
+ interface Notification {
+ method: string;
+ params?: { ... };
+ }
+ ```
+
+## 连接生命周期
+
+### 1. 初始化
+
+
+
+
+1. 客户端发送带有协议版本和功能的“初始化”请求
+2. 服务器以其协议版本和功能进行响应
+3. 客户端发送“已初始化”通知作为确认
+4. 开始正常消息交换
+
+### 2. 消息交换
+
+初始化后,支持以下模式:
+
+* **请求-响应**:客户端或服务器发送请求,对方响应
+* **通知**:任何一方发送单向消息
+
+### 3. 终止
+
+任何一方都可以终止连接:
+
+* 通过 `close()` 干净关闭
+* 传输断开
+* 错误情况
+
+错误处理
+
+MCP 定义了以下标准错误代码:
+
+```typescript
+枚举错误代码 {
+ // 标准 JSON-RPC 错误代码
+ 解析错误 = -32700,
+ 无效请求 = -32600,
+ 方法未找到 = -32601,
+ 无效参数 = -32602,
+ 内部错误 = -32603
+}
+```
+
+SDK 和应用程序可以定义自己的 -32000 以上的错误代码。
+
+错误通过以下方式传播:
+
+* 对请求的错误响应
+* 传输中的错误事件
+* 协议级错误处理程序
+
+## 实现示例
+
+以下是实现 MCP 服务器的一个基本示例:
+
+
+
+ ```typescript
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+
+ const server = new Server({
+ name: "example-server",
+ version: "1.0.0"
+ }, {
+ capabilities: {
+ resources: {}
+ }
+ });
+
+ // Handle requests
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
+ return {
+ resources: [
+ {
+ uri: "example://resource",
+ name: "Example Resource"
+ }
+ ]
+ };
+ });
+
+ // Connect transport
+ const transport = new StdioServerTransport();
+ await server.connect(transport);
+ ```
+
+
+
+ ```python
+ import asyncio
+ import mcp.types as types
+ from mcp.server import Server
+ from mcp.server.stdio import stdio_server
+
+ app = Server("example-server")
+
+ @app.list_resources()
+ async def list_resources() -> list[types.Resource]:
+ return [
+ types.Resource(
+ uri="example://resource",
+ name="Example Resource"
+ )
+ ]
+
+ async def main():
+ async with stdio_server() as streams:
+ await app.run(
+ streams[0],
+ streams[1],
+ app.create_initialization_options()
+ )
+
+ if __name__ == "__main__":
+ asyncio.run(main())
+ ```
+
+
+
+## 最佳实践
+
+### 运输选择
+
+1. **本地通信**
+ * 使用 stdio 传输本地进程
+ * 高效同机通信
+ * 简单的流程管理
+
+2. **远程通信**
+ * 对于需要 HTTP 兼容性的场景使用 SSE
+ * 考虑包括身份验证和授权在内的安全影响
+
+### 消息处理
+
+1. **请求处理**
+ * 彻底验证输入
+ * 使用类型安全模式
+ * 妥善处理错误
+ * 实现超时
+
+2. **进度报告**
+ * 对长时间操作使用进度标记
+ * 逐步报告进度
+ * 包含已知的总体进度
+
+3. **错误管理**
+ * 使用适当的错误代码
+ * 包含有用的错误消息
+ * 错误时清理资源
+
+## 安全考虑
+
+1. **运输安全**
+ * 使用 TLS 进行远程连接
+ * 验证连接来源
+ * 需要时实施身份验证
+
+2. **消息验证**
+ * 验证所有传入消息
+ * 净化输入
+ * 检查消息大小限制
+ * 验证 JSON-RPC 格式
+
+3. **资源保护**
+ * 实施访问控制
+ * 验证资源路径
+ * 监控资源使用情况
+ * 速率限制请求
+
+4. **错误处理**
+ * 不要泄露敏感信息
+ * 记录与安全相关的错误
+ * 实施适当的清理
+ * 处理 DoS 场景
+
+## 调试和监控
+
+1. **日志记录**
+ * 记录协议事件
+ * 跟踪消息流
+ * 监控性能
+ * 记录错误
+
+2. **诊断**
+ * 实施健康检查
+ * 监控连接状态
+ * 跟踪资源使用情况
+ * 概况表现
+
+3. **测试**
+ * 测试不同的传输方式
+ * 验证错误处理
+ * 检查边缘情况
+ * 负载测试服务器
\ No newline at end of file
diff --git a/public/core-architecture-01.png b/public/core-architecture-01.png
new file mode 100644
index 0000000..5a2663c
Binary files /dev/null and b/public/core-architecture-01.png differ
diff --git a/public/core-architecture-02.png b/public/core-architecture-02.png
new file mode 100644
index 0000000..f12fa2c
Binary files /dev/null and b/public/core-architecture-02.png differ
diff --git a/public/server-developers-03.png b/public/server-developers-03.png
new file mode 100644
index 0000000..fb87d91
Binary files /dev/null and b/public/server-developers-03.png differ
diff --git a/public/server-developers-04.png b/public/server-developers-04.png
new file mode 100644
index 0000000..fb87d91
Binary files /dev/null and b/public/server-developers-04.png differ
diff --git a/public/server-developers-05.png b/public/server-developers-05.png
new file mode 100644
index 0000000..6d0b714
Binary files /dev/null and b/public/server-developers-05.png differ
diff --git a/public/server-developers-06.png b/public/server-developers-06.png
new file mode 100644
index 0000000..be14c3d
Binary files /dev/null and b/public/server-developers-06.png differ