#include #include "fiko/mcp/mcp_sunucu.hpp" #include "fiko_test.hpp" using namespace fiko::mcp; namespace { McpSunucu ornekSunucu(int* sayac = nullptr) { McpSunucu s("fikocad", "1.0"); s.aracKaydet({.ad = "yankila", .aciklama = "Verilen metni geri dondurur", .sema = semaNesne({{"metin", semaMetin("yankilanacak metin")}}, {"metin"}), .lisansKimlik = "", .calistir = [sayac](const Json& a) { if (sayac) ++*sayac; return AracSonuc::ok("yanki: " + a["metin"].metinAl()); }}); s.aracKaydet({.ad = "lisansli_is", .aciklama = "Lisans gerektiren islem", .sema = semaNesne({}), .lisansKimlik = "cad.yaz", .calistir = [](const Json&) { return AracSonuc::ok("calisti"); }}); s.aracKaydet({.ad = "patlayan", .aciklama = "Istisna atar", .sema = semaNesne({}), .lisansKimlik = "", .calistir = [](const Json&) -> AracSonuc { throw std::runtime_error("bum"); }}); return s; } } // namespace FIKO_TEST(mcp_initialize_yaniti) { McpSunucu s = ornekSunucu(); const Json y = Json::coz(s.istekIsle( R"({"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}})")); FIKO_KONTROL(y["id"].tamAl() == 1); FIKO_KONTROL(y["result"]["serverInfo"]["name"].metinAl() == "fikocad"); FIKO_KONTROL(y["result"]["protocolVersion"].metinAl() == "2025-06-18"); // istemci sürümü aynen FIKO_KONTROL(y["result"]["capabilities"]["tools"].tip() == JsonTip::Nesne); } FIKO_TEST(mcp_arac_listesi_sema_tasir) { McpSunucu s = ornekSunucu(); const Json y = Json::coz(s.istekIsle(R"({"jsonrpc":"2.0","id":2,"method":"tools/list"})")); const auto& t = y["result"]["tools"].diziAl(); FIKO_KONTROL(t.size() == 3); FIKO_KONTROL(t[0]["name"].metinAl() == "yankila"); FIKO_KONTROL(t[0]["inputSchema"]["type"].metinAl() == "object"); FIKO_KONTROL(t[0]["inputSchema"]["properties"]["metin"]["type"].metinAl() == "string"); FIKO_KONTROL(t[0]["inputSchema"]["required"].diziAl().size() == 1); } FIKO_TEST(mcp_arac_cagirma) { int sayac = 0; McpSunucu s = ornekSunucu(&sayac); const Json y = Json::coz(s.istekIsle( R"({"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"yankila","arguments":{"metin":"selam"}}})")); FIKO_KONTROL(sayac == 1); FIKO_KONTROL(!y["result"]["isError"].mantikAl(true)); FIKO_KONTROL(y["result"]["content"].diziAl()[0]["text"].metinAl() == "yanki: selam"); } FIKO_TEST(mcp_lisans_kapisi_engeller) { McpSunucu s = ornekSunucu(); s.lisansKapisiAyarla([](const std::string& kimlik, std::string& gerekce) { if (kimlik == "cad.yaz") { gerekce = "Yazma hakki lisansiniza dahil degil"; return false; } return true; }); const Json y = Json::coz(s.istekIsle( R"({"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"lisansli_is","arguments":{}}})")); FIKO_KONTROL(y["result"]["isError"].mantikAl()); FIKO_KONTROL(y["result"]["content"].diziAl()[0]["text"].metinAl() == "Yazma hakki lisansiniza dahil degil"); } FIKO_TEST(mcp_lisans_kapisi_izin_verince_calisir) { McpSunucu s = ornekSunucu(); s.lisansKapisiAyarla([](const std::string&, std::string&) { return true; }); const Json y = Json::coz(s.istekIsle( R"({"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"lisansli_is","arguments":{}}})")); FIKO_KONTROL(!y["result"]["isError"].mantikAl(true)); FIKO_KONTROL(y["result"]["content"].diziAl()[0]["text"].metinAl() == "calisti"); } FIKO_TEST(mcp_lisanssiz_arac_kapiya_sorulmaz) { int sayac = 0; McpSunucu s = ornekSunucu(&sayac); bool soruldu = false; s.lisansKapisiAyarla([&](const std::string&, std::string&) { soruldu = true; return false; }); s.istekIsle( R"({"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"yankila","arguments":{"metin":"a"}}})"); FIKO_KONTROL(!soruldu); // lisansKimlik boş → kapı hiç sorulmaz FIKO_KONTROL(sayac == 1); } FIKO_TEST(mcp_arac_istisnasi_sunucuyu_dusurmez) { McpSunucu s = ornekSunucu(); const Json y = Json::coz(s.istekIsle( R"({"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"patlayan","arguments":{}}})")); FIKO_KONTROL(y["result"]["isError"].mantikAl()); FIKO_KONTROL(y["result"]["content"].diziAl()[0]["text"].metinAl().find("bum") != std::string::npos); } FIKO_TEST(mcp_bilinmeyen_arac_ve_yontem) { McpSunucu s = ornekSunucu(); const Json a = Json::coz(s.istekIsle( R"({"jsonrpc":"2.0","id":8,"method":"tools/call","params":{"name":"yok","arguments":{}}})")); FIKO_KONTROL(a["error"]["code"].tamAl() == -32602); const Json b = Json::coz(s.istekIsle(R"({"jsonrpc":"2.0","id":9,"method":"sacma"})")); FIKO_KONTROL(b["error"]["code"].tamAl() == -32601); } FIKO_TEST(mcp_bildirime_yanit_yazilmaz) { McpSunucu s = ornekSunucu(); FIKO_KONTROL(s.istekIsle(R"({"jsonrpc":"2.0","method":"notifications/initialized"})").empty()); FIKO_KONTROL(s.istekIsle(R"({"jsonrpc":"2.0","method":"tools/list"})").empty()); } FIKO_TEST(mcp_bozuk_json_parse_hatasi) { McpSunucu s = ornekSunucu(); const Json y = Json::coz(s.istekIsle("{bozuk")); FIKO_KONTROL(y["error"]["code"].tamAl() == -32700); }