天气信息服务器

基于MCP协议的实时天气信息服务器,通过JSON-RPC 2.0与Claude Desktop通信,提供韩国气象厅官方API的天气数据查询服务。

  • by younwony
  • Java
  • 本地部署
  • 更新于
在 GitHub 查看 younwony/mcp

使用说明

🌤️ Spring AI MCP服务器-天气服务

实施模型上下文协议(MCP)协议的天气信息提供服务器。 通过Claude Desktop和stdio通信连接,利用韩国气象厅官方API提供实时天气信息。

🎯 真正的MCP服务器是?

这个项目(真正的MCP)

Claude (AI) ──stdio/JSON-RPC 2.0──► MCP 서버 ──► 실제 로직 (날씨 API, 계산 등)
   ↑                                    │
   └─── AI가 도구 선택/호출 ─────────────┘
  • 通信方式:stdio(标准I/O)
  • 协议:JSON-RPC 2.0
  • AI位置:客户端(Claude Desktop)
  • 服务器角色:仅提供工具(无AI)

通用AI聊天机器人后端(假MCP)

사용자 ──HTTP──► Spring 서버 ──► OpenAI API
                    │
                    └── 서버가 AI 호출
  • 通信方式:REST API(HTTP)
  • AI位置:服务器端(调用OpenAI)
  • MCP协议:未使用

🚀 快速入门

1.要求事项

  • Java 17或更高版本
  • Gradle 8.5或更高版本
  • Claude Desktop(MCP客户端)
  • 气象厅API密钥(公共数据门户由颁发)

2.设置API密钥

2.1.API密钥发放

  1. 公共数据门户 连接
  2. 注册和登录会员
  3. 搜索“气象厅_短期预报查询服务”
  4. 单击申请使用
  5. 复制已颁发的验证密钥

2.2.注册API密钥

src/main/resources/application.yml 打开文件 service-key 更改值:

weather:
  api:
    service-key: YOUR_API_KEY_HERE

或设置为环境变量:

# Windows
set WEATHER_API_SERVICE_KEY=YOUR_API_KEY_HERE

# macOS/Linux
export WEATHER_API_SERVICE_KEY=YOUR_API_KEY_HERE

3.构建项目

# Windows
.\gradlew clean build

# macOS/Linux
./gradlew clean build

4.Claude桌面设置

视窗: %APPDATA%\Claude\claude_desktop_config.json 添加到文件:

{
  "mcpServers": {
    "weather": {
      "command": "java",
      "args": [
        "-jar",
        "-Dfile.encoding=UTF-8",
        "C:\\workspace\\intellij\\mcp\\build\\libs\\mcp-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}

macOS/Linux: ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "weather": {
      "command": "java",
      "args": [
        "-jar",
        "-Dfile.encoding=UTF-8",
        "/absolute/path/to/mcp/build/libs/mcp-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}

5.重新启动Claude Desktop

要应用设置,请完全退出并重新启动Claude Desktop。

6.使用

在Claude Desktop中,提出以下问题:

서울의 날씨를 알려줘
부산 날씨가 궁금해
위도 37.5665, 경도 126.9780의 초단기 예보를 알려줘

Claude自动调用MCP服务器上的工具,提供实时天气信息!

📦 项目结构

mcp/
├── src/
│   ├── main/
│   │   ├── java/dev/wony/mcp/
│   │   │   ├── McpApplication.java           # Spring Boot 메인 클래스
│   │   │   └── tool/
│   │   │       ├── WeatherService.java       # 날씨 조회 서비스
│   │   │       └── dto/
│   │   │           ├── GridCoordinate.java   # 격자 좌표 변환
│   │   │           ├── WeatherApiResponse.java # API 응답 DTO
│   │   │           ├── WeatherCategory.java  # 날씨 카테고리 enum
│   │   │           ├── WeatherInfo.java      # 날씨 정보 DTO
│   │   │           └── KmaApiResponse.java   # 기상청 API 응답
│   │   └── resources/
│   │       └── application.yml               # 서버 설정 및 API 키
│   └── test/
│       └── java/dev/wony/mcp/tool/
│           ├── WeatherServiceTest.java                  # 단위 테스트
│           ├── WeatherServiceIntegrationTest.java       # 통합 테스트
│           └── dto/
│               ├── GridCoordinateTest.java              # 격자 변환 테스트
│               └── WeatherCategoryTest.java             # 카테고리 테스트
├── docs/
│   ├── KMA_API_GUIDE.md                      # 기상청 API 가이드
│   └── WEATHER_API.md                        # 날씨 API 상세 문서
├── build.gradle                              # Gradle 빌드 설정
├── CLAUDE_SETUP.md                           # Claude Desktop 연동 가이드
└── README.md                                 # 이 파일

🛠️ 提供的工具

1.超短期实况查询(getUltraStrtNcst)

提供以当前时间为基准的实况信息。

输入:

  • latitude (double):纬度(例如37.5665)
  • longitude (double):硬度(例如126.9780)

输出:

=== 초단기실황 (위도: 37.5665, 경도: 126.9780) ===
발표시각: 20241126 1400

기온: 15.2℃
1시간 강수량: 0mm
습도: 65%
강수형태: 없음
풍향: N
풍속: 2.3m/s

发布时间:每小时准时(00:00,01:00,…,23:00)+10分钟后提供

2.超短期预报查询(getUltraStrtFcst)

提供6小时内的预报信息。

输入:

  • latitude (double):纬度
  • longitude (double):硬度

输出:各时段预报(气温、降水、天空状态、风向、风速等)

发布时间:每小时30分钟(00:30,01:30,…,23:30)+15分钟后提供

3.短期预报查询(getVilageFcst)

提供3天预报信息。

输入:

  • latitude (double):纬度
  • longitude (double):硬度

输出:3天时间段详细预报(气温、降水率、降水量、积雪、风向、风速、湿度等)

发布时间:每天8次(02、05、08、11、14、17、20、23时)+10分钟后提供

4.主要城市天气查询(getCurrentWeather)

使用城市名称轻松查询当前天气。

输入:

  • city (String):城市名(首尔、釜山、大邱、仁川、光州、大田、蔚山、世宗、济州之一)

输出:

📍 서울 현재 날씨 (기준시각: 11월 26일 14시)

🌡️ 기온: 15.2°C
🌧️ 1시간 강수량: 없음
💧 습도: 65%
💨 풍속: 2.3m/s
☔ 강수형태: 없음

5.查询支持城市列表(getSupportedCities)

返回可查询天气的城市列表。

输出:

날씨 조회 가능한 도시:
서울, 부산, 대구, 인천, 광주, 대전, 울산, 세종, 제주

主要城市坐标:

  • 首尔:(37.5665,126.9780)
  • 釜山:(35.1796,129.0756)
  • 济州:(33.4996,126.5312)
  • 大田:(36.3504,127.3845)
  • 大邱:(35.8714,128.6014)

参考:纬度将自动转换为气象站网格坐标(nx,ny)。使用Lambert Conformal Conic Projection算法。

🔧 开发指南

添加新工具

  1. src/main/java/dev/wony/mcp/tool/ 在目录中创建新的服务类
  2. @Service 使用注释
  3. 方法 @Tool 添加注释
  4. McpApplication.java在中注册Bean

示例:

package dev.wony.mcp.tool;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

@Service
public class TranslationService {

    @Tool(description = "Translate text to another language")
    public String translate(
        @ToolParam(description = "Text to translate") String text,
        @ToolParam(description = "Target language (e.g., 'Korean', 'English')") String targetLanguage
    ) {
        // 번역 로직 구현
        return "Translated: " + text;
    }
}

而且 McpApplication.java在中注册Bean:

@Bean
public ToolCallbackProvider translationTools(TranslationService translationService) {
    return MethodToolCallbackProvider.builder().toolObjects(translationService).build();
}

外部API集成示例

@Service
public class NewsService {

    @Value("${news.api.key}")
    private String apiKey;

    private final RestClient restClient;

    public NewsService(@Value("${news.api.key}") String apiKey) {
        this.apiKey = apiKey;
        this.restClient = RestClient.builder()
            .baseUrl("https://newsapi.org/v2")
            .build();
    }

    @Tool(description = "Get latest news headlines")
    public String getNews(
        @ToolParam(description = "Country code (e.g., 'kr', 'us')") String country
    ) {
        try {
            NewsResponse response = restClient.get()
                .uri(uriBuilder -> uriBuilder
                    .path("/top-headlines")
                    .queryParam("country", country)
                    .queryParam("apiKey", apiKey)
                    .build())
                .retrieve()
                .body(NewsResponse.class);

            return formatNewsResponse(response);
        } catch (RestClientException e) {
            return "뉴스 조회 실패: " + e.getMessage();
        }
    }
}

🧪 测试

运行单元测试

# Windows
.\gradlew test

# macOS/Linux
./gradlew test

运行集成测试

集成测试调用实际气象站API,因此需要API密钥。

# Windows
.\gradlew test --tests "*IntegrationTest"

# macOS/Linux
./gradlew test --tests "*IntegrationTest"

测试覆盖率报告

.\gradlew test jacocoTestReport

报告: build/reports/jacoco/test/html/index.html

📚 技术堆栈

  • Java 17:最新LTS版本
  • 弹簧靴3.5.8:企业级框架
  • 春季AI 1.1.0:实施MCP协议
  • 8.5级:构建工具
  • Rest客户端:HTTP客户端
  • JUnit5和AssertJ:测试框架

解决问题

服务器未连接

  1. 验证路径: claude_desktop_config.json验证的JAR路径是否正确
  2. 验证版本: .\gradlew clean build重新构建到
  3. 检查日志:
    • 窗户: %APPDATA%\Claude\logs\
    • macOS: ~/Library/Logs/Claude/

工具不起作用

  1. 确认注释: @Service哇 @Tool 确认是否全部存在
  2. 扫描包: dev.wony.mcp.tool 检查包中是否存在
  3. Bean注册: McpApplication.java在 ToolCallbackProvider 验证Bean是否已注册
  4. 重新构建:代码更改后必须重新构建

API响应错误

  1. 验证API密钥: application.yml确保在中设置了正确的API密钥
  2. 呼叫限制:气象局API有流量限制,请注意过度呼叫
  3. 发布时间:根据每个API的发布时间更新数据,以确认时间

Java版本错误

java -version  # Java 17 이상 확인

如果没有Java 17 艾多普蒂姆请从下载。

🔍 MCP协议工作原理

1.初始化(Initialization)

当Claude Desktop启动MCP服务器时:

→ Claude: {"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}
← Server: {"jsonrpc":"2.0","result":{"protocolVersion":"1.0.0"},"id":1}

2.查看工具列表

→ Claude: {"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}
← Server: {
    "jsonrpc":"2.0",
    "result":{
      "tools":[
        {"name":"getUltraSrtNcst","description":"Get current weather observation..."},
        {"name":"getUltraSrtFcst","description":"Get ultra short-term forecast..."},
        {"name":"getVilageFcst","description":"Get short-term forecast..."},
        {"name":"getCurrentWeather","description":"한국 주요 도시의 현재 날씨를 조회..."},
        {"name":"getSupportedCities","description":"날씨 조회가 가능한 한국 주요 도시 목록..."}
      ]
    },
    "id":2
  }

3.调用工具

→ Claude: {
    "jsonrpc":"2.0",
    "method":"tools/call",
    "params":{
      "name":"getCurrentWeather",
      "arguments":{"city":"서울"}
    },
    "id":3
  }
← Server: {
    "jsonrpc":"2.0",
    "result":"📍 서울 현재 날씨 (기준시각: 11월 26일 14시)\n\n🌡️ 기온: 15.2°C\n...",
    "id":3
  }

🔗 参考资料

📝 许可证

MIT许可证

🤝 贡献

请将错误报告或功能建议登记为问题!


由...制作❤️ 通过 dev.wony

该服务器实现了真正的MCP协议。不使用REST API或HTTP通信,直接通过Claude Desktop和stdio进行通信。