UNPKG

@hakan.ucar/kandilli-mcp

Version:

Kandilli Rasathanesi üzerinden son depremleri sorgulamak için bir Model Context Protocol (MCP) aracıdır

253 lines (252 loc) 9.56 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import * as cheerio from "cheerio"; const TOOLS = [ { name: "son_depremler", description: "Son depremleri listeler (varsayılan: son 50 deprem)", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Gösterilecek maksimum deprem sayısı", default: 50 }, min_buyukluk: { type: "number", description: "Minimum deprem büyüklüğü (ML)", default: 0 } } } }, { name: "istanbul_depremleri", description: "İstanbul ve Marmara bölgesindeki depremleri listeler", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Gösterilecek maksimum deprem sayısı", default: 20 }, saat_icerisinde: { type: "number", description: "Son kaç saat içindeki depremler (0=tümü)", default: 0 } } } }, { name: "buyuk_depremler", description: "Büyük depremleri listeler (ML ≥ 4.0 varsayılan)", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Gösterilecek maksimum deprem sayısı", default: 10 }, min_buyukluk: { type: "number", description: "Minimum deprem büyüklüğü (ML)", default: 4.0 }, gun_icerisinde: { type: "number", description: "Son kaç gün içindeki depremler (0=tümü)", default: 7 } } } }, { name: "son_saat_depremleri", description: "Son 1 saat içindeki depremleri listeler", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Gösterilecek maksimum deprem sayısı", default: 30 } } } } ]; async function getSonDepremler() { const url = 'http://www.koeri.boun.edu.tr/scripts/lst5.asp'; try { const response = await fetch(url); const text = await response.text(); const $ = cheerio.load(text); const preText = $("pre").text().trim(); if (!preText) throw new Error('Deprem verisi bulunamadı'); const lines = preText.split("\n").slice(6) || []; const depremler = []; // Satır başlıklarını atla (ilk 5 satır) for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (!line.trim()) continue; try { const tarihStr = line.slice(0, 10).trim(); const saatStr = line.slice(11, 19).trim(); //Tarih validasyon if (!/^\d{4}\.\d{2}\.\d{2}$/.test(tarihStr) || !/^\d{2}:\d{2}:\d{2}$/.test(saatStr)) { continue; } const date = new Date(`${tarihStr.replace(/\./g, '-')}T${saatStr}+03:00`); const deprem = { tarih: { raw: `${tarihStr} ${saatStr}`, timestamp: date.getTime(), iso: date.toISOString() }, konum: { enlem: line.slice(20, 28).trim(), boylam: line.slice(29, 40).trim(), derinlikKm: line.slice(41, 55).trim(), yer: line.slice(71, 119).trim() }, buyukluk: { MD: parseNullableFloat(line.slice(55, 58)), ML: parseNullableFloat(line.slice(60, 63)), Mw: parseNullableFloat(line.slice(65, 68)) }, id: generateDepremId(line) // Opsiyonel unique ID }; depremler.push(deprem); } catch (err) { console.error(`Satır parse hatası (${i}):`, err); } } return { metadata: { kaynak: 'Boğaziçi Üniversitesi Kandilli Rasathanesi', sonGuncelleme: new Date().toISOString(), toplamDeprem: depremler.length }, depremler }; } catch (error) { console.error('Hata:', error); throw new Error('Deprem verileri alınamadı'); } } // HELPER FUNCTIONS function parseNullableFloat(str) { const val = str.trim(); return val === '-.-' ? null : parseFloat(val); } function generateDepremId(line) { // Tarih + Saat + Enlem + Boylam hash'i const hash = line.substr(0, 19).replace(/\s/g, ''); return `deprem-${hash}`; } // Tool handler async function handleToolCall(name, args) { try { const data = await getSonDepremler(); let filteredDepremler = []; let baslik = ""; switch (name) { case "son_depremler": filteredDepremler = data.depremler .filter(d => args.min_buyukluk ? (d.buyukluk.ML || 0) >= args.min_buyukluk : true) .slice(0, args.limit || 50); baslik = `Son ${filteredDepremler.length} Deprem` + (args.min_buyukluk ? ` (ML ≥ ${args.min_buyukluk})` : ""); break; case "istanbul_depremleri": filteredDepremler = data.depremler .filter(d => (d.konum.yer.includes('İSTANBUL') || d.konum.yer.includes('MARMARA')) && (args.saat_icerisinde ? d.tarih.timestamp > Date.now() - (args.saat_icerisinde * 3600000) : true)) .slice(0, args.limit || 20); baslik = `İstanbul/Marmara Depremleri` + (args.saat_icerisinde ? ` (Son ${args.saat_icerisinde} Saat)` : ""); break; case "buyuk_depremler": filteredDepremler = data.depremler .filter(d => (d.buyukluk.ML || 0) >= (args.min_buyukluk || 4.0) && (args.gun_icerisinde ? d.tarih.timestamp > Date.now() - (args.gun_icerisinde * 86400000) : true)) .sort((a, b) => (b.buyukluk.ML || 0) - (a.buyukluk.ML || 0)) .slice(0, args.limit || 10); baslik = `Büyük Depremler (ML ≥ ${args.min_buyukluk || 4.0})` + (args.gun_icerisinde ? ` (Son ${args.gun_icerisinde} Gün)` : ""); break; case "son_saat_depremleri": const birSaatOnce = Date.now() - 3600000; filteredDepremler = data.depremler .filter(d => d.tarih.timestamp > birSaatOnce) .slice(0, args.limit || 30); baslik = "Son 1 Saatteki Depremler"; break; default: return { content: [{ type: "text", text: `Bilinmeyen tool: ${name}` }], isError: true }; } const formattedText = formatDepremSonuc({ baslik, depremler: filteredDepremler }); return { content: [{ type: "text", text: formattedText }], isError: false }; } catch (error) { return { content: [{ type: "text", text: `Hata: ${error.message}` }], isError: true }; } } // Yardımcı fonksiyon: Deprem sonuçlarını formatlama function formatDepremSonuc(result) { let text = `=== ${result.baslik} ===\n`; if (result.depremler.length === 0) { return text + "Kayıt bulunamadı"; } //text += JSON.stringify(result.depremler, null, 2) result.depremler.forEach((dep, i) => { text += `\n${i + 1}. [${dep.tarih.raw}]\n` + ` → Büyüklük: ML ${dep.buyukluk.ML}, Derinlik: ${dep.konum.derinlikKm} km\n` + ` → Yer : ${dep.konum.yer}\n` + ` → Konum: ${dep.konum.enlem}°N ${dep.konum.boylam}°E`; }); return text; } // Server setup const server = new Server({ name: "kandilli-server", version: "0.1.0" }, { capabilities: { tools: {} } }); server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, req => handleToolCall(req.params.name, req.params.arguments)); // Server başlatma async function start() { const transport = new StdioServerTransport(); await server.connect(transport); } start().catch(err => { console.error('Server hatası:', err); process.exit(1); }); // Temizlik process.on('SIGINT', () => { server.close(); process.exit(); });