Extends `X-Idempotency-Key` header usage to `DELETE` and `PUT` requests, ensuring idempotent behavior for a wider range of modifying API operations. Updates the documentation and client implementation for `DELETE` requests. Refactors `handleResponse` to robustly parse API responses. It now reads the response body once as text, enabling graceful handling of non-JSON error bodies and consistent processing of successful or empty responses.
702 lines
23 KiB
Markdown
702 lines
23 KiB
Markdown
# 🌩️ iklim.co MCP Server
|
||
|
||
[Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for the iklim.co Weather API. AI asistanların (Claude, OpenClaw vb.) iklim.co'nun hava durumu, yıldırım, fırtına, yağış ve alarm API'lerine doğal dil ile erişmesini sağlar.
|
||
|
||
## 📋 İçindekiler
|
||
|
||
- [🌐 Genel Bakış](#-genel-bakış)
|
||
- [⚙️ Gereksinimler](#️-gereksinimler)
|
||
- [🚀 Kurulum](#-kurulum)
|
||
- [🔧 Ortam Değişkenleri](#-ortam-değişkenleri)
|
||
- [▶️ Build ve Çalıştırma](#️-build-ve-çalıştırma)
|
||
- [🔌 MCP Client Konfigürasyonu](#-mcp-client-konfigürasyonu)
|
||
- [Claude CLI (.mcp.json)](#claude-cli-mcpjson)
|
||
- [OpenClaw](#openclaw)
|
||
- [Diğer MCP İstemcileri](#diğer-mcp-i̇stemcileri)
|
||
- [🛠️ Araç Kataloğu](#️-araç-kataloğu)
|
||
- [⚡ Yıldırım / Lightning](#-yıldırım--lightning)
|
||
- [🌪️ Fırtına / Thunderstorm](#️-fırtına--thunderstorm)
|
||
- [🌧️ Yağış / Precipitation](#️-yağış--precipitation)
|
||
- [🌤️ Hava Tahmini / Forecast](#️-hava-tahmini--forecast)
|
||
- [👤 Auth & Kullanıcı](#-auth--kullanıcı)
|
||
- [🏢 Hesap / Account](#-hesap--account)
|
||
- [📍 Nokta Alarmları / Point Alarms](#-nokta-alarmları--point-alarms)
|
||
- [🗺️ Coğrafi Alarmlar / Geo Alarms](#️-coğrafi-alarmlar--geo-alarms)
|
||
- [📅 Tahmin Alarmları / Forecast Alarms](#-tahmin-alarmları--forecast-alarms)
|
||
- [🏗️ Mimari](#️-mimari)
|
||
- [🔐 Kimlik Doğrulama ve Güvenlik](#-kimlik-doğrulama-ve-güvenlik)
|
||
- [Dahili Auth Akışı](#dahili-auth-akışı)
|
||
- [JWT Token Yaşam Döngüsü](#jwt-token-yaşam-döngüsü)
|
||
- [HTTP İstek Header'ları](#http-i̇stek-headerları)
|
||
- [HMAC-SHA256 İmza Hesabı](#hmac-sha256-i̇mza-hesabı)
|
||
- [Auth ile Normal İstekler Arasındaki Fark](#auth-ile-normal-i̇stekler-arasındaki-fark)
|
||
- [Güvenlik Önerileri](#güvenlik-önerileri)
|
||
- [💻 Geliştirici Notları](#-geliştirici-notları)
|
||
|
||
---
|
||
|
||
## 🌐 Genel Bakış
|
||
|
||
Bu MCP server, iklim.co REST API'sinin tüm yeteneklerini **57 araç** (tool) olarak sunar. Araçlar 9 kategoriye ayrılmıştır:
|
||
|
||
| Kategori | Araç Sayısı | Kapsam |
|
||
|----------|:-----------:|--------|
|
||
| ⚡ Lightning | 2 | Yıldırım çarpma verileri |
|
||
| 🌪️ Thunderstorm | 3 | Fırtına hücresi takibi |
|
||
| 🌧️ Precipitation | 2 | Radar yağış verileri |
|
||
| 🌤️ Forecast | 3 | Saatlik / günlük / anlık tahmin |
|
||
| 👤 Auth & User | 11 | Kimlik doğrulama, kullanıcı yönetimi |
|
||
| 🏢 Account | 8 | Hesap ve abonelik yönetimi |
|
||
| 📍 Point Alarms | 6 | Nokta tabanlı uyarı abonelikleri |
|
||
| 🗺️ Geo Alarms | 12 | Coğrafi sınır bazlı uyarılar + il/ilçe/mahalle kataloğu |
|
||
| 📅 Forecast Alarms | 10 | Eşik bazlı tahmin uyarıları + il/ilçe kataloğu |
|
||
| **Toplam** | **57** | |
|
||
|
||
---
|
||
|
||
## ⚙️ Gereksinimler
|
||
|
||
- **Node.js** >= 18 (ES2022 desteği gerekli)
|
||
- **npm** >= 9
|
||
- iklim.co API erişim bilgileri (HMAC secret, kullanıcı adı ve şifre)
|
||
|
||
---
|
||
|
||
## 🚀 Kurulum
|
||
|
||
```bash
|
||
cd mcp-server
|
||
npm install
|
||
npm run build
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Ortam Değişkenleri
|
||
|
||
Server başlamadan önce aşağıdaki değişkenlerin tanımlı olması gerekir. Geliştirme ortamında `.env` dosyası oluşturabilirsiniz (projenin `.gitignore` dosyasına ekli):
|
||
|
||
```bash
|
||
# .env
|
||
IKLIM_ENV=test # prod | test | local (IKLIM_BASE_URL yoksa kullanılır)
|
||
IKLIM_BASE_URL= # Opsiyonel. Tanımlıysa IKLIM_ENV'i override eder
|
||
IKLIM_HMAC_SECRET=<secret> # Zorunlu. İstek imzalama için HMAC-SHA256 anahtarı
|
||
IKLIM_USERNAME=<email> # Zorunlu. API kullanıcı e-postası
|
||
IKLIM_PASSWORD=<password> # Zorunlu. API kullanıcı şifresi
|
||
```
|
||
|
||
**🌍 Ortama göre base URL:**
|
||
|
||
| `IKLIM_ENV` | URL |
|
||
|-------------|-----|
|
||
| `prod` | `https://api.iklim.co` |
|
||
| `test` | `https://api-test.iklim.co` |
|
||
| `local` | `http://localhost:8080` |
|
||
|
||
---
|
||
|
||
## ▶️ Build ve Çalıştırma
|
||
|
||
```bash
|
||
# TypeScript'i derle (dist/ klasörünü oluşturur)
|
||
npm run build
|
||
|
||
# Derlenmiş server'ı başlat
|
||
npm start
|
||
|
||
# Geliştirme modunda çalıştır (derleme gerekmez, ts-node kullanır)
|
||
npm run dev
|
||
```
|
||
|
||
Başarılı başlatmada çıktı:
|
||
```
|
||
iklim.co MCP server running
|
||
```
|
||
|
||
> Server **stdio** transportu üzerinden iletişim kurar — doğrudan terminal ile çalıştırmak yerine bir MCP istemcisi tarafından yönetilmesi beklenir.
|
||
|
||
---
|
||
|
||
## 🔌 MCP Client Konfigürasyonu
|
||
|
||
### Claude CLI (.mcp.json)
|
||
|
||
Projenin kök dizinindeki `.mcp.json` dosyası Claude CLI tarafından otomatik olarak yüklenir:
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"iklim": {
|
||
"command": "node",
|
||
"args": ["/tam/yol/mcp-server/dist/index.js"],
|
||
"env": {
|
||
"IKLIM_ENV": "test",
|
||
"IKLIM_HMAC_SECRET": "<secret>",
|
||
"IKLIM_USERNAME": "<email>",
|
||
"IKLIM_PASSWORD": "<password>"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Global olarak tanımlamak için `~/.claude/settings.json` içine aynı `mcpServers` bloğunu ekleyin.
|
||
|
||
### OpenClaw
|
||
|
||
`openclaw mcp set` komutu `env` parametresini desteklemez. Tüm alanlar tek satır JSON olarak geçirilmeli, `env` de dahil:
|
||
|
||
```bash
|
||
openclaw mcp set iklim '{"type":"stdio","command":"node","args":["/tam/yol/mcp-server/dist/index.js"],"env":{"IKLIM_ENV":"test","IKLIM_HMAC_SECRET":"<secret>","IKLIM_USERNAME":"<email>","IKLIM_PASSWORD":"<password>"}}'
|
||
```
|
||
|
||
Veya `~/.openclaw/openclaw.json` içinde `mcp` bölümüne doğrudan ekleyin (okunabilir format):
|
||
|
||
```json
|
||
{
|
||
"mcp": {
|
||
"iklim": {
|
||
"type": "stdio",
|
||
"command": "node",
|
||
"args": ["/tam/yol/mcp-server/dist/index.js"],
|
||
"env": {
|
||
"IKLIM_ENV": "test",
|
||
"IKLIM_HMAC_SECRET": "<secret>",
|
||
"IKLIM_USERNAME": "<email>",
|
||
"IKLIM_PASSWORD": "<password>"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Diğer MCP İstemcileri
|
||
|
||
MCP stdio standardını destekleyen her istemci kullanılabilir. Gerekli bilgiler:
|
||
|
||
- **transport**: `stdio`
|
||
- **command**: `node`
|
||
- **args**: `["<dist/index.js tam yolu>"]`
|
||
- **env**: Yukarıdaki dört değişken
|
||
|
||
---
|
||
|
||
## 🛠️ Araç Kataloğu
|
||
|
||
### ⚡ Yıldırım / Lightning
|
||
|
||
#### `get_lightnings_within`
|
||
Belirli bir merkez noktası ve yarıçap içindeki yıldırım çarpmalarını sorgular.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `latitude` | number | Merkez enlem (-90 / 90) |
|
||
| `longitude` | number | Merkez boylam (-180 / 180) |
|
||
| `radius` | number | Yarıçap, metre (0 – 50.000) |
|
||
| `backwardInterval` | number | Geriye dönük süre, saniye (60 – 2.592.000 / 30 gün) |
|
||
| `endTimeEpoch` | number | Sorgu bitiş zamanı, epoch ms |
|
||
| `pageNumber` | number? | Sayfa numarası (default: 0) |
|
||
| `pageSize` | number? | Sayfa boyutu, max 100 (default: 10) |
|
||
|
||
#### `get_lightnings_page`
|
||
Zaman aralığına göre yıldırım verilerini sayfalı olarak getirir.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `backwardInterval` | number | Geriye dönük süre, saniye (60 – 432.000 / 5 gün) |
|
||
| `endTimeEpoch` | number | Sorgu bitiş zamanı, epoch ms |
|
||
| `pageNumber` | number? | Sayfa numarası |
|
||
| `pageSize` | number? | Sayfa boyutu, max 100 |
|
||
|
||
---
|
||
|
||
### 🌪️ Fırtına / Thunderstorm
|
||
|
||
#### `get_thunderstorms_within`
|
||
Yarıçap içindeki fırtına hücrelerini sorgular.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `latitude` | number | Merkez enlem |
|
||
| `longitude` | number | Merkez boylam |
|
||
| `radius` | number | Yarıçap, metre (0 – 50.000) |
|
||
| `backwardInterval` | number | Geriye dönük süre, saniye (60 – 2.592.000) |
|
||
| `endTimeEpoch` | number | Bitiş zamanı, epoch ms |
|
||
| `intersectsWith` | string? | `THREAT_POLYGON` veya `CELL_POLYGON` |
|
||
| `pageNumber` | number? | |
|
||
| `pageSize` | number? | |
|
||
|
||
#### `get_thunderstorms_page`
|
||
Zaman aralığına göre fırtına verilerini sayfalı getirir.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `backwardInterval` | number | Geriye dönük süre, saniye (60 – 432.000) |
|
||
| `endTimeEpoch` | number | Bitiş zamanı, epoch ms |
|
||
| `pageNumber` | number? | |
|
||
| `pageSize` | number? | |
|
||
|
||
#### `get_thunderstorm_details`
|
||
Belirli bir fırtına olayının geçmiş detaylarını getirir.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `eventId` | string | Örn: `EVT20240413001` |
|
||
| `pageNumber` | number? | |
|
||
| `pageSize` | number? | |
|
||
|
||
---
|
||
|
||
### 🌧️ Yağış / Precipitation
|
||
|
||
#### `get_precipitations_within`
|
||
Dairesel alan içindeki radar yağış verilerini sorgular.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `latitude` | number | Merkez enlem |
|
||
| `longitude` | number | Merkez boylam |
|
||
| `radius` | number | Yarıçap, metre (0 – 50.000) |
|
||
| `backwardInterval` | number | Geriye dönük süre, saniye (60 – 2.592.000) |
|
||
| `endTimeEpoch` | number | Bitiş zamanı, epoch ms |
|
||
| `intensityThreshold` | string? | Min. yoğunluk: `DRIZZLE` < `LIGHT` < `MODERATE` < `HEAVY` < `VERY_HEAVY` < `EXTREME` |
|
||
| `pageNumber` | number? | |
|
||
| `pageSize` | number? | |
|
||
|
||
#### `get_precipitations_page`
|
||
Zaman aralığına göre yağış verilerini sayfalı getirir. `intensityThreshold` **zorunludur**.
|
||
|
||
---
|
||
|
||
### 🌤️ Hava Tahmini / Forecast
|
||
|
||
#### `get_hourly_forecast`
|
||
Saatlik hava durumu tahminlerini getirir (1–14 gün).
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `latitude` | number | Enlem |
|
||
| `longitude` | number | Boylam |
|
||
| `forecastDays` | number? | 1–14, default 7 |
|
||
| `metrics` | string[]? | İstenilen metrik listesi (bkz. aşağısı) |
|
||
| `startTime` | string? | ISO 8601 başlangıç zamanı |
|
||
| `solarPanelTiltForRadiation` | number? | Panel eğim açısı (radyasyon metriği için) |
|
||
| `solarPanelAzimuthForRadiation` | number? | Panel azimut açısı |
|
||
|
||
<details>
|
||
<summary>📊 Desteklenen metrikler (53 adet)</summary>
|
||
|
||
`WEATHER_ICON`, `TEMPERATURE`, `APPARENT_TEMPERATURE`, `DEW_POINT_TEMPERATURE`, `HUMIDITY`, `CLOUD_COVER`, `CLOUD_COVER_LOW`, `CLOUD_COVER_MID`, `CLOUD_COVER_HIGH`, `WIND_SPEED`, `WIND_GUST`, `WIND_DIRECTION`, `WIND_SPEED_AT_100M`, `WIND_DIRECTION_AT_100M`, `PRECIPITATION`, `RAIN`, `SHOWERS`, `SNOWFALL`, `SNOW_DEPTH`, `PRECIPITATION_PROBABILITY`, `WEATHER_CODE`, `PRESSURE_MSL`, `SURFACE_PRESSURE`, `VISIBILITY`, `EVAPOTRANSPIRATION`, `ET0_FAO_EVAPOTRANSPIRATION`, `VAPOUR_PRESSURE_DEFICIT`, `CAPE`, `LIFTED_INDEX`, `CONVECTIVE_INHIBITION`, `SUNSHINE_DURATION`, `SHORTWAVE_RADIATION`, `DIRECT_RADIATION`, `DIFFUSE_RADIATION`, `DIRECT_NORMAL_IRRADIANCE`, `GLOBAL_TILTED_IRRADIANCE`, `TERRESTRIAL_RADIATION`, `SHORTWAVE_RADIATION_INSTANT`, `DIRECT_RADIATION_INSTANT`, `DIFFUSE_RADIATION_INSTANT`, `DIRECT_NORMAL_IRRADIANCE_INSTANT`, `GLOBAL_TILTED_IRRADIANCE_INSTANT`, `TERRESTRIAL_RADIATION_INSTANT`, `SOIL_TEMPERATURE_0CM`, `SOIL_TEMPERATURE_6CM`, `SOIL_TEMPERATURE_18CM`, `SOIL_TEMPERATURE_54CM`, `SOIL_MOISTURE_0_TO_1CM`, `SOIL_MOISTURE_1_TO_3CM`, `SOIL_MOISTURE_3_TO_9CM`, `SOIL_MOISTURE_9_TO_27CM`, `SOIL_MOISTURE_27_TO_81CM`, `IS_DAY`
|
||
</details>
|
||
|
||
#### `get_daily_forecast`
|
||
Günlük agregat tahminleri getirir. Parametreler `get_hourly_forecast` ile aynıdır (`solarPanel*` parametreleri hariç).
|
||
|
||
#### `get_current_weather`
|
||
Konum için anlık (en güncel) hava verilerini getirir.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `latitude` | number | Enlem |
|
||
| `longitude` | number | Boylam |
|
||
| `metrics` | string[]? | Yukarıdaki metrik listesinden seçim |
|
||
|
||
---
|
||
|
||
### 👤 Auth & Kullanıcı
|
||
|
||
#### `auth_register`
|
||
Yeni kullanıcı kaydı oluşturur.
|
||
|
||
| Parametre | Tip |
|
||
|-----------|-----|
|
||
| `username` | string (e-posta) |
|
||
| `password` | string |
|
||
| `firstName` | string |
|
||
| `lastName` | string |
|
||
| `midName` | string? |
|
||
| `locale` | string? |
|
||
| `timezone` | string? |
|
||
|
||
#### `auth_logout`
|
||
Geçerli JWT token'ı geçersiz kılar.
|
||
|
||
#### `user_get_me`
|
||
Oturum açmış kullanıcının profilini getirir.
|
||
|
||
#### `user_get`
|
||
`userId` ile kullanıcı detayını getirir.
|
||
|
||
#### `user_create`
|
||
_(Admin)_ Yeni kullanıcı oluşturur. `roles` ve `status` zorunludur.
|
||
|
||
#### `user_update`
|
||
_(Admin)_ `userId` ile kullanıcı alanlarını günceller.
|
||
|
||
#### `user_list`
|
||
Kullanıcı listesini sayfalı getirir. `roles`, `status`, `pageNumber`, `pageSize` ile filtrelenir.
|
||
|
||
#### `user_unblock`
|
||
Bloke edilmiş kullanıcıyı açar.
|
||
|
||
#### `user_change_password`
|
||
`oldPassword` ve `newPassword` ile şifre değiştirir.
|
||
|
||
#### `user_password_reset_request`
|
||
Şifre sıfırlama e-postası gönderir. `userName` ve `passwordResetPageLink` gerekir.
|
||
|
||
#### `user_password_reset`
|
||
Sıfırlama token'ı ile şifre günceller. `userId`, `token`, `newPassword`, `loginPageLink` gerekir.
|
||
|
||
---
|
||
|
||
### 🏢 Hesap / Account
|
||
|
||
#### `account_get`
|
||
`userId` ile hesap detaylarını getirir.
|
||
|
||
#### `account_create`
|
||
Yeni hesap oluşturur.
|
||
|
||
| Parametre | Tip | Değerler |
|
||
|-----------|-----|----------|
|
||
| `type` | string | `INDIVIDUAL` \| `ORGANIZATION` |
|
||
| `subscriptionPlan` | string | `NONE` \| `TRIAL` \| `BASIC_MONTHLY` \| `BASIC_YEARLY` \| `PREMIUM_MONTHLY` \| `PREMIUM_YEARLY` \| `CUSTOM` |
|
||
| `mobilePhoneNumber` | string? | |
|
||
| `location` | string? | |
|
||
| `company` | string? | |
|
||
| `industry` | string? | |
|
||
| `profilePictureUrl` | string? | |
|
||
|
||
#### `account_update`
|
||
`accountId` ile hesap alanlarını günceller.
|
||
|
||
#### `account_activation_request`
|
||
Aktivasyon e-postası gönderir.
|
||
|
||
#### `account_activate`
|
||
E-posta doğrulama token'ı ile hesabı aktive eder.
|
||
|
||
#### `account_phone_activation_request`
|
||
SMS doğrulama kodu gönderir.
|
||
|
||
#### `account_activate_phone`
|
||
SMS token'ı ile telefonu doğrular.
|
||
|
||
#### `account_update_subscription`
|
||
Abonelik planını değiştirir.
|
||
|
||
---
|
||
|
||
### 📍 Nokta Alarmları / Point Alarms
|
||
|
||
Belirli bir GPS koordinatı ve yarıçap etrafındaki olaylar için uyarı abonelikleri.
|
||
|
||
#### `point_alarm_register`
|
||
Yeni nokta alarmı oluşturur.
|
||
|
||
| Parametre | Tip | Açıklama |
|
||
|-----------|-----|----------|
|
||
| `recipientId` | string | Uyarı alıcısı ID |
|
||
| `latitude` | number | Merkez enlem |
|
||
| `longitude` | number | Merkez boylam |
|
||
| `radius` | number | Yarıçap, metre (0 – 50.000) |
|
||
| `lightningFilter` | object? | Yıldırım filtresi |
|
||
| `thunderstormFilter` | object? | Fırtına filtresi |
|
||
| `precipitationFilter` | object? | Yağış filtresi |
|
||
| `webhook` | object? | Webhook konfigürasyonu |
|
||
|
||
#### `point_alarm_update`
|
||
Mevcut kaydı günceller.
|
||
|
||
#### `point_alarm_delete`
|
||
Alarm kaydını siler.
|
||
|
||
#### `point_alarm_get_by_id`
|
||
Tekil alarm detayını getirir.
|
||
|
||
#### `point_alarm_get_by_recipient`
|
||
Alıcıya ait tüm alarmları listeler.
|
||
|
||
#### `point_alarm_list`
|
||
Sayfalı alarm listesi. `recipientIds` ile filtreleme yapılabilir.
|
||
|
||
---
|
||
|
||
### 🗺️ Coğrafi Alarmlar / Geo Alarms
|
||
|
||
İdari sınır, poligon veya H3 adresi bazlı uyarı abonelikleri.
|
||
|
||
#### `geo_alarm_register`
|
||
Yeni coğrafi alarm oluşturur. Üç sınır tipi desteklenir:
|
||
|
||
```json
|
||
// İdari sınır
|
||
{ "type": "ADMINISTRATIVE", "cityId": 6, "districtId": 60 }
|
||
|
||
// Poligon
|
||
{ "type": "POLYGON", "polygon": { "exterior": [{"lat": 39.9, "lng": 32.8}, ...] } }
|
||
|
||
// H3 hücre indeksi
|
||
{ "type": "H3INDEX", "h3Address": "8f2830828052d25" }
|
||
```
|
||
|
||
#### `geo_alarm_update` / `geo_alarm_delete` / `geo_alarm_get_by_id` / `geo_alarm_get_by_recipient` / `geo_alarm_list`
|
||
Nokta alarmlarıyla aynı imza.
|
||
|
||
#### 🏙️ Konum Kataloğu
|
||
|
||
| Araç | Açıklama |
|
||
|------|----------|
|
||
| `geo_alarm_list_cities` | Tüm illeri listeler |
|
||
| `geo_alarm_get_city` | `cityId` ile il detayı |
|
||
| `geo_alarm_list_districts` | `cityId` ile ilçeleri listeler |
|
||
| `geo_alarm_get_district` | `districtId` ile ilçe detayı |
|
||
| `geo_alarm_list_neighbourhoods` | `districtId` ile mahalleleri listeler |
|
||
| `geo_alarm_get_neighbourhood` | `neighbourhoodId` ile mahalle detayı |
|
||
|
||
---
|
||
|
||
### 📅 Tahmin Alarmları / Forecast Alarms
|
||
|
||
Eşik aşıldığında sabah (04:00 UTC) veya akşam (16:00 UTC) uyarı gönderir.
|
||
|
||
#### `forecast_alarm_register`
|
||
Yeni tahmin alarmı oluşturur.
|
||
|
||
**Sınır tipleri:**
|
||
```json
|
||
{ "type": "ADMINISTRATIVE", "cityId": 6, "districtId": 60 }
|
||
{ "type": "POINT", "latitude": 39.92, "longitude": 32.85 }
|
||
```
|
||
|
||
**⚠️ Eşik parametreleri:**
|
||
|
||
| Parametre | Değerler |
|
||
|-----------|----------|
|
||
| `precipitationThreshold` | mm cinsinden sayısal değer |
|
||
| `snowFallThreshold` | `LIGHT` \| `MODERATE` \| `HEAVY` |
|
||
| `windGustThreshold` | `STRONG_WIND` \| `STORM` \| `SEVERE_STORM` \| `HURRICANE` |
|
||
| `hotTemperatureThreshold` | `HOT_SNAP` \| `HEAVY_HOT_SNAP` \| `EXTREME_HOT_SNAP` |
|
||
| `coldTemperatureThreshold` | `COLD_SNAP` \| `HEAVY_COLD_SNAP` \| `EXTREME_COLD_SNAP` |
|
||
|
||
**📬 Teslimat:**
|
||
|
||
| Parametre | Açıklama |
|
||
|-----------|----------|
|
||
| `forecastDays` | 1–7, kaç günlük tahmin |
|
||
| `forecastAlarmDelivery` | `MORNING` (04:00 UTC) \| `EVENING` (16:00 UTC) |
|
||
|
||
#### `forecast_alarm_update` / `forecast_alarm_delete` / `forecast_alarm_get_by_id` / `forecast_alarm_get_by_recipient` / `forecast_alarm_list`
|
||
Nokta alarmlarıyla aynı imza.
|
||
|
||
#### 🏙️ Konum Kataloğu
|
||
|
||
| Araç | Açıklama |
|
||
|------|----------|
|
||
| `forecast_alarm_list_cities` | Tüm illeri listeler |
|
||
| `forecast_alarm_get_city` | `cityId` ile il detayı |
|
||
| `forecast_alarm_list_districts` | `cityId` ile ilçeleri listeler |
|
||
| `forecast_alarm_get_district` | `districtId` ile ilçe detayı |
|
||
|
||
---
|
||
|
||
## 🏗️ Mimari
|
||
|
||
```
|
||
src/
|
||
├── index.ts # MCP server başlatma, tool routing
|
||
├── config.ts # Ortam değişkenleri
|
||
├── auth.ts # JWT token yönetimi (otomatik yenileme)
|
||
├── client.ts # HTTP API istemcisi (HMAC imzalama)
|
||
├── security.ts # HMAC-SHA256, nonce, idempotency key
|
||
└── tools/
|
||
├── lightnings.ts
|
||
├── thunderstorms.ts
|
||
├── precipitations.ts
|
||
├── forecasts.ts
|
||
├── auth.ts
|
||
├── accounts.ts
|
||
├── point-alarms.ts
|
||
├── geo-alarms.ts
|
||
└── forecast-alarms.ts
|
||
```
|
||
|
||
**İstek akışı:**
|
||
|
||
```
|
||
MCP İstemci
|
||
│
|
||
▼
|
||
index.ts (CallToolRequestSchema)
|
||
│
|
||
▼
|
||
tools/<kategori>.ts ← Zod validasyonu
|
||
│
|
||
▼
|
||
client.ts (apiGet / apiPost / apiPatch / apiDelete)
|
||
│ ├── auth.ts → geçerli JWT token al (gerekirse otomatik yenile)
|
||
│ └── security.ts → HMAC-SHA256 imzası üret
|
||
│
|
||
▼
|
||
iklim.co REST API
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 Kimlik Doğrulama ve Güvenlik
|
||
|
||
API ile iletişim iki katmanlı güvenlik mekanizması üzerine kuruludur: **JWT tabanlı kimlik doğrulama** ve **HMAC-SHA256 istek imzalama**. Her ikisi de her istekte birlikte kullanılır.
|
||
|
||
### Dahili Auth Akışı
|
||
|
||
Server ilk araç çağrısında otomatik olarak login olur; bu işlem dışarıdan tetiklenmez, tamamen içseldir.
|
||
|
||
```
|
||
İlk araç çağrısı
|
||
│
|
||
▼
|
||
getValidAccessToken() ← auth.ts
|
||
│
|
||
├─ tokenState yok → login()
|
||
│ POST /v1/auth/login
|
||
│ { username, password }
|
||
│ ← { accessToken, refreshToken }
|
||
│ JWT payload decode → expiry hesapla
|
||
│ tokenState'e kaydet
|
||
│
|
||
├─ accessToken süresi dolmak üzere (< 30 sn kaldı) → refresh()
|
||
│ POST /v1/auth/refresh
|
||
│ { refreshToken }
|
||
│ ← { accessToken, refreshToken }
|
||
│ tokenState güncelle
|
||
│
|
||
└─ accessToken geçerli → doğrudan döndür
|
||
```
|
||
|
||
> ⚠️ **Önemli:** `login` ve `refresh` endpoint'leri `Authorization: Bearer` header'ı **içermez** — bu istekler yalnızca HMAC imzasıyla doğrulanır (bkz. aşağısı).
|
||
|
||
### JWT Token Yaşam Döngüsü
|
||
|
||
Token state bellekte (`tokenState`) tutulur ve her araç çağrısından önce kontrol edilir:
|
||
|
||
```
|
||
tokenState = {
|
||
accessToken: string // API isteklerinde kullanılan JWT
|
||
refreshToken: string // accessToken yenileme için
|
||
accessTokenExpiresAt: number // epoch ms (JWT payload'dan decode edilir)
|
||
refreshTokenExpiresAt: number // epoch ms
|
||
}
|
||
```
|
||
|
||
Karar ağacı (`EXPIRY_BUFFER_MS = 30.000 ms`):
|
||
|
||
```
|
||
now < accessTokenExpiresAt - 30s → mevcut token'ı kullan
|
||
now < refreshTokenExpiresAt - 30s → refresh token ile yenile
|
||
aksi hâlde → yeniden login ol
|
||
```
|
||
|
||
30 saniyelik tampon, istek transit süresinde token'ın geçersiz kalması riskini ortadan kaldırır.
|
||
|
||
### HTTP İstek Header'ları
|
||
|
||
Her API isteğine (`login` ve `refresh` dahil) aşağıdaki header'lar eklenir:
|
||
|
||
| Header | Değer | Açıklama |
|
||
|--------|-------|----------|
|
||
| `Content-Type` | `application/json` | Sabit |
|
||
| `Authorization` | `Bearer <accessToken>` | Yalnızca normal API isteklerinde; login/refresh'te **yoktur** |
|
||
| `X-Signature` | hex string | HMAC-SHA256 imzası (bkz. aşağısı) |
|
||
| `X-Timestamp` | `Date.now()` string | Unix epoch, milisaniye |
|
||
| `X-Nonce` | UUID v4 | Her istekte tekil, replay saldırısı önleme |
|
||
| `X-Idempotency-Key` | UUID v4 | `POST`, `PUT`, `PATCH` ve `DELETE` isteklerinde |
|
||
|
||
### HMAC-SHA256 İmza Hesabı
|
||
|
||
`X-Signature` değeri şu dört bileşenin `|` ile birleştirilmesinden elde edilen string'in HMAC-SHA256'sıdır:
|
||
|
||
```
|
||
imzalanacak_veri = "METHOD|PATH_WITH_QUERY|TIMESTAMP|BODY"
|
||
X-Signature = HMAC-SHA256(imzalanacak_veri, IKLIM_HMAC_SECRET) → hex
|
||
```
|
||
|
||
**Bileşenler:**
|
||
|
||
| Bileşen | Açıklama | Örnek |
|
||
|---------|----------|-------|
|
||
| `METHOD` | HTTP metodu, büyük harf | `POST` |
|
||
| `PATH_WITH_QUERY` | Sorgu parametreleri dahil path | `/v1/lightnings/within` veya `/v1/users?page=0` |
|
||
| `TIMESTAMP` | `X-Timestamp` ile aynı değer | `1774349677000` |
|
||
| `BODY` | JSON body string; body yoksa boş string `""` | `{"username":"..."}` |
|
||
|
||
**Örnek hesaplama (GET isteği):**
|
||
|
||
```
|
||
METHOD = "GET"
|
||
PATH = "/v1/users?pageNumber=0&pageSize=10"
|
||
TIMESTAMP = "1774349677000"
|
||
BODY = "" ← GET isteğinde body yok
|
||
|
||
imzalanacak = "GET|/v1/users?pageNumber=0&pageSize=10|1774349677000|"
|
||
X-Signature = HMAC-SHA256(imzalanacak, secret) → "a3f9c2..."
|
||
```
|
||
|
||
**Örnek hesaplama (POST isteği):**
|
||
|
||
```
|
||
METHOD = "POST"
|
||
PATH = "/v1/lightnings/within"
|
||
TIMESTAMP = "1774349677000"
|
||
BODY = '{"center":{"lat":39.87,"lng":32.74},"radius":50000,...}'
|
||
|
||
imzalanacak = "POST|/v1/lightnings/within|1774349677000|{\"center\":...}"
|
||
X-Signature = HMAC-SHA256(imzalanacak, secret) → "7be41d..."
|
||
```
|
||
|
||
> Kaynak: [`src/security.ts`](src/security.ts) — `buildSignature()` fonksiyonu
|
||
|
||
### Auth ile Normal İstekler Arasındaki Fark
|
||
|
||
| | `POST /v1/auth/login` | `POST /v1/auth/refresh` | Normal API İstekleri |
|
||
|---|---|---|---|
|
||
| `Authorization` | ❌ | ❌ | ✅ `Bearer <token>` |
|
||
| `X-Signature` | ✅ | ✅ | ✅ |
|
||
| `X-Timestamp` | ✅ | ✅ | ✅ |
|
||
| `X-Nonce` | ✅ | ✅ | ✅ |
|
||
| `X-Idempotency-Key` | ✅ | ✅ | ✅ (POST/PUT/PATCH/DELETE) |
|
||
|
||
### Güvenlik Önerileri
|
||
|
||
- 🔒 `IKLIM_HMAC_SECRET` ve `IKLIM_PASSWORD` değerlerini kaynak koda veya git geçmişine eklemeyin
|
||
- 🏭 Üretim ortamında `.env` dosyası yerine sistem ortam değişkenlerini veya secret manager kullanın
|
||
- 🌍 Her ortam (prod/test/local) için ayrı kimlik bilgileri kullanın
|
||
- 🔄 HMAC secret'ı düzenli olarak rotate edin
|
||
|
||
---
|
||
|
||
## 💻 Geliştirici Notları
|
||
|
||
**➕ Yeni araç eklemek**
|
||
|
||
1. `src/tools/` altında ilgili dosyaya yeni tool tanımı ve handler ekle
|
||
2. `src/index.ts` içinde `toolHandlerMap`'e ve `allTools` dizisine kaydet
|
||
3. `npm run build` ile derle
|
||
|
||
**✅ Zod şemaları**
|
||
|
||
Tüm araç girdileri Zod ile çalışma zamanında doğrulanır. Her araç `schema.parse(args)` çağrısından geçer; geçersiz girdi anlamlı bir hata mesajıyla geri döner.
|
||
|
||
**🔧 TypeScript derleme hedefi**
|
||
|
||
`tsconfig.json` → `target: ES2022`, `module: Node16`
|
||
|
||
**📦 Bağımlılıklar**
|
||
|
||
| Paket | Versiyon | Kullanım |
|
||
|-------|----------|----------|
|
||
| `@modelcontextprotocol/sdk` | ^1.0.0 | MCP altyapısı |
|
||
| `zod` | ^3.23.8 | Girdi validasyonu |
|
||
| `typescript` | ^5.5.0 | Derleme |
|
||
| `ts-node` | ^10.9.2 | Geliştirme modu |
|