#include "fiko/mcp/mcp_sunucu.hpp" namespace fiko::mcp { Json semaNesne(JsonNesne alanlar, std::vector zorunlu) { Json s = Json::nesne(); s.ekle("type", Json::metin("object")); s.ekle("properties", Json::nesne(std::move(alanlar))); if (!zorunlu.empty()) { Json z = Json::dizi(); for (auto& a : zorunlu) z.it(Json::metin(a)); s.ekle("required", std::move(z)); } return s; } static Json semaTemel(const char* tip, const std::string& aciklama) { Json s = Json::nesne(); s.ekle("type", Json::metin(tip)); s.ekle("description", Json::metin(aciklama)); return s; } Json semaMetin(const std::string& a) { return semaTemel("string", a); } Json semaSayi(const std::string& a) { return semaTemel("number", a); } Json semaMantik(const std::string& a) { return semaTemel("boolean", a); } namespace { Json yanitGovde(const Json& id, Json sonuc) { Json y = Json::nesne(); y.ekle("jsonrpc", Json::metin("2.0")); y.ekle("id", id); y.ekle("result", std::move(sonuc)); return y; } Json yanitHata(const Json& id, int kod, const std::string& mesaj) { Json h = Json::nesne(); h.ekle("code", Json::tam(kod)); h.ekle("message", Json::metin(mesaj)); Json y = Json::nesne(); y.ekle("jsonrpc", Json::metin("2.0")); y.ekle("id", id.varMi() ? id : Json::bos()); y.ekle("error", std::move(h)); return y; } // MCP araç sonucu: {content:[{type:"text",text:...}], isError:bool} Json aracIcerik(const AracSonuc& s) { Json parca = Json::nesne(); parca.ekle("type", Json::metin("text")); parca.ekle("text", Json::metin(s.metin)); Json dizi = Json::dizi(); dizi.it(std::move(parca)); Json sonuc = Json::nesne(); sonuc.ekle("content", std::move(dizi)); sonuc.ekle("isError", Json::mantik(s.hata)); return sonuc; } } // namespace Json McpSunucu::aracListesi() const { Json dizi = Json::dizi(); for (const auto& a : araclar_) { Json t = Json::nesne(); t.ekle("name", Json::metin(a.ad)); t.ekle("description", Json::metin(a.aciklama)); t.ekle("inputSchema", a.sema.tip() == JsonTip::Nesne ? a.sema : semaNesne({})); dizi.it(std::move(t)); } Json sonuc = Json::nesne(); sonuc.ekle("tools", std::move(dizi)); return sonuc; } Json McpSunucu::aracCagir(const Json& params, bool& hataVar) { hataVar = false; const std::string ad = params["name"].metinAl(); const Json& args = params["arguments"]; for (const auto& a : araclar_) { if (a.ad != ad) continue; // LİSANS KAPISI — araç gövdesi çalışmadan ÖNCE. if (!a.lisansKimlik.empty() && lisansKapisi_) { std::string gerekce; if (!lisansKapisi_(a.lisansKimlik, gerekce)) { return aracIcerik(AracSonuc::hataliDon( gerekce.empty() ? "Bu islem lisansiniza dahil degil: " + a.ad : gerekce)); } } if (!a.calistir) return aracIcerik(AracSonuc::hataliDon("Arac govdesi yok: " + ad)); // Araç istisnası sunucuyu düşürmez (uzun ömürlü stdio süreci). try { return aracIcerik(a.calistir(args)); } catch (const std::exception& e) { return aracIcerik(AracSonuc::hataliDon(std::string("Arac istisnasi: ") + e.what())); } catch (...) { return aracIcerik(AracSonuc::hataliDon("Arac bilinmeyen istisna")); } } hataVar = true; return Json::metin("Bilinmeyen arac: " + ad); } std::string McpSunucu::istekIsle(const std::string& satir) { std::string cozHata; const Json istek = Json::coz(satir, &cozHata); if (!istek.varMi() || istek.tip() != JsonTip::Nesne) return yanitHata(Json::bos(), -32700, "JSON ayristirilamadi: " + cozHata).yaz(); const Json& id = istek["id"]; const std::string yontem = istek["method"].metinAl(); // Bildirim (id yok) → yanıt YAZILMAZ (JSON-RPC 2.0). const bool bildirim = !id.varMi() || id.tip() == JsonTip::Bos; if (yontem == "initialize") { Json yetenek = Json::nesne(); yetenek.ekle("tools", Json::nesne()); Json bilgi = Json::nesne(); bilgi.ekle("name", Json::metin(ad_)); bilgi.ekle("version", Json::metin(surum_)); Json sonuc = Json::nesne(); // İstemcinin istediği sürümü aynen kabul et (bilinmiyorsa kendi tabanımız). const std::string istenen = istek["params"]["protocolVersion"].metinAl(); sonuc.ekle("protocolVersion", Json::metin(istenen.empty() ? "2024-11-05" : istenen)); sonuc.ekle("capabilities", std::move(yetenek)); sonuc.ekle("serverInfo", std::move(bilgi)); return bildirim ? std::string() : yanitGovde(id, std::move(sonuc)).yaz(); } if (yontem == "notifications/initialized" || yontem == "notifications/cancelled") return {}; // bildirim → sessiz if (yontem == "ping") return bildirim ? std::string() : yanitGovde(id, Json::nesne()).yaz(); if (yontem == "tools/list") return bildirim ? std::string() : yanitGovde(id, aracListesi()).yaz(); if (yontem == "tools/call") { bool hataVar = false; Json sonuc = aracCagir(istek["params"], hataVar); if (bildirim) return {}; if (hataVar) return yanitHata(id, -32602, sonuc.metinAl()).yaz(); return yanitGovde(id, std::move(sonuc)).yaz(); } if (bildirim) return {}; return yanitHata(id, -32601, "Desteklenmeyen yontem: " + yontem).yaz(); } } // namespace fiko::mcp