first commit
This commit is contained in:
@@ -0,0 +1,701 @@
|
||||
# 🌩️ 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 | Yalnızca `POST` ve `PATCH` 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/PATCH) |
|
||||
|
||||
### 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 |
|
||||
Reference in New Issue
Block a user