flatten parameters

This commit is contained in:
saidsurucu
2025-05-28 18:42:16 +03:00
parent 12bb62cd9c
commit 3bcf2bbf2a
8 changed files with 320 additions and 35 deletions
+1 -1
View File
@@ -232,7 +232,7 @@ class AnayasaBireyselBasvuruApiClient:
markdown_text = None markdown_text = None
temp_file_path = None temp_file_path = None
try: try:
md_converter = MarkItDown(enable_plugins=False) md_converter = MarkItDown()
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file:
if not html_input_for_markdown.strip().lower().startswith(("<html", "<!doctype")): if not html_input_for_markdown.strip().lower().startswith(("<html", "<!doctype")):
tmp_file.write(f"<html><head><meta charset=\"UTF-8\"></head><body>{html_input_for_markdown}</body></html>") tmp_file.write(f"<html><head><meta charset=\"UTF-8\"></head><body>{html_input_for_markdown}</body></html>")
+1 -1
View File
@@ -224,7 +224,7 @@ class AnayasaMahkemesiApiClient:
markdown_text = None markdown_text = None
temp_file_path = None temp_file_path = None
try: try:
md_converter = MarkItDown(enable_plugins=False) md_converter = MarkItDown()
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file:
# Ensure the content is wrapped in basic HTML structure if it's not already # Ensure the content is wrapped in basic HTML structure if it's not already
if not html_input_for_markdown.strip().lower().startswith(("<html", "<!doctype")): if not html_input_for_markdown.strip().lower().startswith(("<html", "<!doctype")):
+1 -1
View File
@@ -126,7 +126,7 @@ class DanistayApiClient:
markdown_text = None markdown_text = None
temp_file_path = None temp_file_path = None
try: try:
md_converter = MarkItDown(enable_plugins=False) # Basic conversion md_converter = MarkItDown() # Basic conversion
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file:
tmp_file.write(html_input_for_markdown) # Write the full HTML string tmp_file.write(html_input_for_markdown) # Write the full HTML string
+1 -1
View File
@@ -116,7 +116,7 @@ class EmsalApiClient:
markdown_text = None markdown_text = None
temp_file_path = None temp_file_path = None
try: try:
md_converter = MarkItDown(enable_plugins=False) md_converter = MarkItDown()
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file:
tmp_file.write(html_input_for_markdown) tmp_file.write(html_input_for_markdown)
+313 -28
View File
@@ -4,8 +4,8 @@ import atexit
import logging import logging
import os import os
from pydantic import HttpUrl, Field from pydantic import HttpUrl, Field
from typing import Optional, Dict from typing import Optional, Dict, List, Literal
import urllib.parse # urllib.parse client tarafında kullanılıyor, server'da gerekmeyebilir. import urllib.parse
# --- Logging Configuration Start --- # --- Logging Configuration Start ---
LOG_DIRECTORY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logs") LOG_DIRECTORY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logs")
@@ -49,7 +49,8 @@ from emsal_mcp_module.models import (
) )
from uyusmazlik_mcp_module.client import UyusmazlikApiClient from uyusmazlik_mcp_module.client import UyusmazlikApiClient
from uyusmazlik_mcp_module.models import ( from uyusmazlik_mcp_module.models import (
UyusmazlikSearchRequest, UyusmazlikSearchResponse, UyusmazlikDocumentMarkdown UyusmazlikSearchRequest, UyusmazlikSearchResponse, UyusmazlikDocumentMarkdown,
UyusmazlikBolumEnum, UyusmazlikTuruEnum, UyusmazlikKararSonucuEnum
) )
from anayasa_mcp_module.client import AnayasaMahkemesiApiClient from anayasa_mcp_module.client import AnayasaMahkemesiApiClient
from anayasa_mcp_module.bireysel_client import AnayasaBireyselBasvuruApiClient from anayasa_mcp_module.bireysel_client import AnayasaBireyselBasvuruApiClient
@@ -60,6 +61,8 @@ from anayasa_mcp_module.models import (
AnayasaBireyselReportSearchRequest, AnayasaBireyselReportSearchRequest,
AnayasaBireyselReportSearchResult, AnayasaBireyselReportSearchResult,
AnayasaBireyselBasvuruDocumentMarkdown, AnayasaBireyselBasvuruDocumentMarkdown,
AnayasaDonemEnum, AnayasaBasvuruTuruEnum, AnayasaVarYokEnum,
AnayasaNormTuruEnum, AnayasaIncelemeSonucuEnum, AnayasaSonucGerekcesiEnum
) )
# KIK Module Imports # KIK Module Imports
from kik_mcp_module.client import KikApiClient from kik_mcp_module.client import KikApiClient
@@ -72,7 +75,7 @@ from kik_mcp_module.models import (
app = FastMCP( app = FastMCP(
name="TurkishLawResearchAssistantMCP", name="YargiMCP",
instructions="MCP server for TR legal databases (Yargitay, Danistay, Emsal, Uyusmazlik, Anayasa-Norm, Anayasa-Bireysel, KIK).", instructions="MCP server for TR legal databases (Yargitay, Danistay, Emsal, Uyusmazlik, Anayasa-Norm, Anayasa-Bireysel, KIK).",
dependencies=["httpx", "beautifulsoup4", "markitdown", "pydantic", "aiohttp", "playwright"] dependencies=["httpx", "beautifulsoup4", "markitdown", "pydantic", "aiohttp", "playwright"]
) )
@@ -87,10 +90,46 @@ anayasa_bireysel_client_instance = AnayasaBireyselBasvuruApiClient()
kik_client_instance = KikApiClient() kik_client_instance = KikApiClient()
# --- MCP Tools for Yargitay --- # --- MCP Tools for Yargitay ---
# ... (Yargıtay araçları öncekiyle aynı, docstringler İngilizce) ...
@app.tool() @app.tool()
async def search_yargitay_detailed(search_query: YargitayDetailedSearchRequest) -> CompactYargitaySearchResult: async def search_yargitay_detailed(
arananKelime: str = Field("", description="Keyword to search for."),
birimYrgKurulDaire: str = Field("", description="Yargitay Board Unit (e.g., 'Hukuk Genel Kurulu')."),
birimYrgHukukDaire: str = Field("", description="Yargitay Civil Chamber (e.g., '1. Hukuk Dairesi')."),
birimYrgCezaDaire: str = Field("", description="Yargitay Criminal Chamber."),
esasYil: str = Field("", description="Case year for 'Esas No'."),
esasIlkSiraNo: str = Field("", description="Starting sequence number for 'Esas No'."),
esasSonSiraNo: str = Field("", description="Ending sequence number for 'Esas No'."),
kararYil: str = Field("", description="Decision year for 'Karar No'."),
kararIlkSiraNo: str = Field("", description="Starting sequence number for 'Karar No'."),
kararSonSiraNo: str = Field("", description="Ending sequence number for 'Karar No'."),
baslangicTarihi: str = Field("", description="Start date for decision search (DD.MM.YYYY)."),
bitisTarihi: str = Field("", description="End date for decision search (DD.MM.YYYY)."),
siralama: str = Field("3", description="Sorting criteria (1: Esas No, 2: Karar No, 3: Karar Tarihi)."),
siralamaDirection: str = Field("desc", description="Sorting direction ('asc' or 'desc')."),
pageSize: int = Field(10, ge=1, le=100, description="Number of results per page."),
pageNumber: int = Field(1, ge=1, description="Page number to retrieve.")
) -> CompactYargitaySearchResult:
"""Searches Yargitay (Court of Cassation) decisions using detailed criteria.""" """Searches Yargitay (Court of Cassation) decisions using detailed criteria."""
search_query = YargitayDetailedSearchRequest(
arananKelime=arananKelime,
birimYrgKurulDaire=birimYrgKurulDaire,
birimYrgHukukDaire=birimYrgHukukDaire,
birimYrgCezaDaire=birimYrgCezaDaire,
esasYil=esasYil,
esasIlkSiraNo=esasIlkSiraNo,
esasSonSiraNo=esasSonSiraNo,
kararYil=kararYil,
kararIlkSiraNo=kararIlkSiraNo,
kararSonSiraNo=kararSonSiraNo,
baslangicTarihi=baslangicTarihi,
bitisTarihi=bitisTarihi,
siralama=siralama,
siralamaDirection=siralamaDirection,
pageSize=pageSize,
pageNumber=pageNumber
)
logger.info(f"Tool 'search_yargitay_detailed' called: {search_query.model_dump_json(exclude_none=True, indent=2)}") logger.info(f"Tool 'search_yargitay_detailed' called: {search_query.model_dump_json(exclude_none=True, indent=2)}")
try: try:
api_response = await yargitay_client_instance.search_detailed_decisions(search_query) api_response = await yargitay_client_instance.search_detailed_decisions(search_query)
@@ -103,7 +142,7 @@ async def search_yargitay_detailed(search_query: YargitayDetailedSearchRequest)
logger.warning("API response for Yargitay search did not contain expected data structure.") logger.warning("API response for Yargitay search did not contain expected data structure.")
return CompactYargitaySearchResult(decisions=[], total_records=0, requested_page=search_query.pageNumber, page_size=search_query.pageSize) return CompactYargitaySearchResult(decisions=[], total_records=0, requested_page=search_query.pageNumber, page_size=search_query.pageSize)
except Exception as e: except Exception as e:
logger.exception(f"Error in tool 'search_yargitay_detailed'.") # Query loglaması kaldırıldı, PII içerebilir logger.exception(f"Error in tool 'search_yargitay_detailed'.")
raise raise
@app.tool() @app.tool()
@@ -118,11 +157,27 @@ async def get_yargitay_document_markdown(document_id: str) -> YargitayDocumentMa
raise raise
# --- MCP Tools for Danistay --- # --- MCP Tools for Danistay ---
# ... (Danıştay araçları öncekiyle aynı, docstringler İngilizce) ...
@app.tool() @app.tool()
async def search_danistay_by_keyword(search_query: DanistayKeywordSearchRequest) -> CompactDanistaySearchResult: async def search_danistay_by_keyword(
andKelimeler: List[str] = Field(default_factory=list, description="Keywords for AND logic, e.g., ['word1', 'word2']"),
orKelimeler: List[str] = Field(default_factory=list, description="Keywords for OR logic."),
notAndKelimeler: List[str] = Field(default_factory=list, description="Keywords for NOT AND logic."),
notOrKelimeler: List[str] = Field(default_factory=list, description="Keywords for NOT OR logic."),
pageNumber: int = Field(1, ge=1, description="Page number."),
pageSize: int = Field(10, ge=1, le=100, description="Results per page.")
) -> CompactDanistaySearchResult:
"""Searches Danıştay (Council of State) decisions using keywords.""" """Searches Danıştay (Council of State) decisions using keywords."""
logger.info(f"Tool 'search_danistay_by_keyword' called.") # Query loglaması kaldırıldı
search_query = DanistayKeywordSearchRequest(
andKelimeler=andKelimeler,
orKelimeler=orKelimeler,
notAndKelimeler=notAndKelimeler,
notOrKelimeler=notOrKelimeler,
pageNumber=pageNumber,
pageSize=pageSize
)
logger.info(f"Tool 'search_danistay_by_keyword' called.")
try: try:
api_response = await danistay_client_instance.search_keyword_decisions(search_query) api_response = await danistay_client_instance.search_keyword_decisions(search_query)
if api_response.data: if api_response.data:
@@ -138,9 +193,46 @@ async def search_danistay_by_keyword(search_query: DanistayKeywordSearchRequest)
raise raise
@app.tool() @app.tool()
async def search_danistay_detailed(search_query: DanistayDetailedSearchRequest) -> CompactDanistaySearchResult: async def search_danistay_detailed(
daire: Optional[str] = Field(None, description="Chamber/Department name (e.g., '1. Daire')."),
esasYil: Optional[str] = Field(None, description="Case year for 'Esas No'."),
esasIlkSiraNo: Optional[str] = Field(None, description="Starting sequence for 'Esas No'."),
esasSonSiraNo: Optional[str] = Field(None, description="Ending sequence for 'Esas No'."),
kararYil: Optional[str] = Field(None, description="Decision year for 'Karar No'."),
kararIlkSiraNo: Optional[str] = Field(None, description="Starting sequence for 'Karar No'."),
kararSonSiraNo: Optional[str] = Field(None, description="Ending sequence for 'Karar No'."),
baslangicTarihi: Optional[str] = Field(None, description="Start date for decision (DD.MM.YYYY)."),
bitisTarihi: Optional[str] = Field(None, description="End date for decision (DD.MM.YYYY)."),
mevzuatNumarasi: Optional[str] = Field(None, description="Legislation number."),
mevzuatAdi: Optional[str] = Field(None, description="Legislation name."),
madde: Optional[str] = Field(None, description="Article number."),
siralama: str = Field("1", description="Sorting criteria (e.g., 1: Esas No, 3: Karar Tarihi)."),
siralamaDirection: str = Field("desc", description="Sorting direction ('asc' or 'desc')."),
pageNumber: int = Field(1, ge=1, description="Page number."),
pageSize: int = Field(10, ge=1, le=100, description="Results per page.")
) -> CompactDanistaySearchResult:
"""Performs a detailed search for Danıştay (Council of State) decisions.""" """Performs a detailed search for Danıştay (Council of State) decisions."""
logger.info(f"Tool 'search_danistay_detailed' called.") # Query loglaması kaldırıldı
search_query = DanistayDetailedSearchRequest(
daire=daire,
esasYil=esasYil,
esasIlkSiraNo=esasIlkSiraNo,
esasSonSiraNo=esasSonSiraNo,
kararYil=kararYil,
kararIlkSiraNo=kararIlkSiraNo,
kararSonSiraNo=kararSonSiraNo,
baslangicTarihi=baslangicTarihi,
bitisTarihi=bitisTarihi,
mevzuatNumarasi=mevzuatNumarasi,
mevzuatAdi=mevzuatAdi,
madde=madde,
siralama=siralama,
siralamaDirection=siralamaDirection,
pageNumber=pageNumber,
pageSize=pageSize
)
logger.info(f"Tool 'search_danistay_detailed' called.")
try: try:
api_response = await danistay_client_instance.search_detailed_decisions(search_query) api_response = await danistay_client_instance.search_detailed_decisions(search_query)
if api_response.data: if api_response.data:
@@ -167,11 +259,47 @@ async def get_danistay_document_markdown(document_id: str) -> DanistayDocumentMa
raise raise
# --- MCP Tools for Emsal --- # --- MCP Tools for Emsal ---
# ... (Emsal araçları öncekiyle aynı, docstringler İngilizce) ...
@app.tool() @app.tool()
async def search_emsal_detailed_decisions(search_query: EmsalSearchRequest) -> CompactEmsalSearchResult: async def search_emsal_detailed_decisions(
keyword: Optional[str] = Field(None, description="Keyword to search."),
selected_bam_civil_court: Optional[str] = Field(None, description="Selected BAM Civil Court."),
selected_civil_court: Optional[str] = Field(None, description="Selected Civil Court."),
selected_regional_civil_chambers: List[str] = Field(default_factory=list, description="Selected Regional Civil Chambers."),
case_year_esas: Optional[str] = Field(None, description="Case year for 'Esas No'."),
case_start_seq_esas: Optional[str] = Field(None, description="Starting sequence for 'Esas No'."),
case_end_seq_esas: Optional[str] = Field(None, description="Ending sequence for 'Esas No'."),
decision_year_karar: Optional[str] = Field(None, description="Decision year for 'Karar No'."),
decision_start_seq_karar: Optional[str] = Field(None, description="Starting sequence for 'Karar No'."),
decision_end_seq_karar: Optional[str] = Field(None, description="Ending sequence for 'Karar No'."),
start_date: Optional[str] = Field(None, description="Start date for decision (DD.MM.YYYY)."),
end_date: Optional[str] = Field(None, description="End date for decision (DD.MM.YYYY)."),
sort_criteria: str = Field("1", description="Sorting criteria (e.g., 1: Esas No)."),
sort_direction: str = Field("desc", description="Sorting direction ('asc' or 'desc')."),
page_number: int = Field(1, ge=1, description="Page number."),
page_size: int = Field(10, ge=1, le=100, description="Results per page.")
) -> CompactEmsalSearchResult:
"""Searches for Emsal (UYAP Precedent) decisions using detailed criteria.""" """Searches for Emsal (UYAP Precedent) decisions using detailed criteria."""
logger.info(f"Tool 'search_emsal_detailed_decisions' called.") # Query loglaması kaldırıldı
search_query = EmsalSearchRequest(
keyword=keyword,
selected_bam_civil_court=selected_bam_civil_court,
selected_civil_court=selected_civil_court,
selected_regional_civil_chambers=selected_regional_civil_chambers,
case_year_esas=case_year_esas,
case_start_seq_esas=case_start_seq_esas,
case_end_seq_esas=case_end_seq_esas,
decision_year_karar=decision_year_karar,
decision_start_seq_karar=decision_start_seq_karar,
decision_end_seq_karar=decision_end_seq_karar,
start_date=start_date,
end_date=end_date,
sort_criteria=sort_criteria,
sort_direction=sort_direction,
page_number=page_number,
page_size=page_size
)
logger.info(f"Tool 'search_emsal_detailed_decisions' called.")
try: try:
api_response = await emsal_client_instance.search_detailed_decisions(search_query) api_response = await emsal_client_instance.search_detailed_decisions(search_query)
if api_response.data: if api_response.data:
@@ -199,13 +327,56 @@ async def get_emsal_document_markdown(document_id: str) -> EmsalDocumentMarkdown
raise raise
# --- MCP Tools for Uyusmazlik --- # --- MCP Tools for Uyusmazlik ---
# ... (Uyuşmazlık araçları öncekiyle aynı, docstringler İngilizce) ...
@app.tool() @app.tool()
async def search_uyusmazlik_decisions( async def search_uyusmazlik_decisions(
search_params: UyusmazlikSearchRequest icerik: str = Field("", description="Keyword or content for main text search."),
bolum: Literal["", "Ceza Bölümü", "Genel Kurul Kararları", "Hukuk Bölümü"] = Field("", description="Select the department (Bölüm)."),
uyusmazlik_turu: Literal["", "Görev Uyuşmazlığı", "Hüküm Uyuşmazlığı"] = Field("", description="Select the type of dispute."),
karar_sonuclari: List[Literal["Hüküm Uyuşmazlığı Olmadığına Dair", "Hüküm Uyuşmazlığı Olduğuna Dair"]] = Field(default_factory=list, description="List of desired 'Karar Sonucu' types."),
esas_yil: str = Field("", description="Case year ('Esas Yılı')."),
esas_sayisi: str = Field("", description="Case number ('Esas Sayısı')."),
karar_yil: str = Field("", description="Decision year ('Karar Yılı')."),
karar_sayisi: str = Field("", description="Decision number ('Karar Sayısı')."),
kanun_no: str = Field("", description="Relevant Law Number."),
karar_date_begin: str = Field("", description="Decision start date (DD.MM.YYYY)."),
karar_date_end: str = Field("", description="Decision end date (DD.MM.YYYY)."),
resmi_gazete_sayi: str = Field("", description="Official Gazette number."),
resmi_gazete_date: str = Field("", description="Official Gazette date (DD.MM.YYYY)."),
tumce: str = Field("", description="Exact phrase search."),
wild_card: str = Field("", description="Search for phrase and its inflections."),
hepsi: str = Field("", description="Search for texts containing all specified words."),
herhangi_birisi: str = Field("", description="Search for texts containing any of the specified words."),
not_hepsi: str = Field("", description="Exclude texts containing these specified words.")
) -> UyusmazlikSearchResponse: ) -> UyusmazlikSearchResponse:
"""Searches for Uyuşmazlık Mahkemesi (Court of Jurisdictional Disputes) decisions using various criteria.""" """Searches for Uyuşmazlık Mahkemesi (Court of Jurisdictional Disputes) decisions using various criteria."""
logger.info(f"Tool 'search_uyusmazlik_decisions' called.") # Query loglaması kaldırıldı
# Convert string literals to enums
bolum_enum = UyusmazlikBolumEnum(bolum) if bolum else UyusmazlikBolumEnum.TUMU
uyusmazlik_turu_enum = UyusmazlikTuruEnum(uyusmazlik_turu) if uyusmazlik_turu else UyusmazlikTuruEnum.TUMU
karar_sonuclari_enums = [UyusmazlikKararSonucuEnum(ks) for ks in karar_sonuclari]
search_params = UyusmazlikSearchRequest(
icerik=icerik,
bolum=bolum_enum,
uyusmazlik_turu=uyusmazlik_turu_enum,
karar_sonuclari=karar_sonuclari_enums,
esas_yil=esas_yil,
esas_sayisi=esas_sayisi,
karar_yil=karar_yil,
karar_sayisi=karar_sayisi,
kanun_no=kanun_no,
karar_date_begin=karar_date_begin,
karar_date_end=karar_date_end,
resmi_gazete_sayi=resmi_gazete_sayi,
resmi_gazete_date=resmi_gazete_date,
tumce=tumce,
wild_card=wild_card,
hepsi=hepsi,
herhangi_birisi=herhangi_birisi,
not_hepsi=not_hepsi
)
logger.info(f"Tool 'search_uyusmazlik_decisions' called.")
try: try:
return await uyusmazlik_client_instance.search_decisions(search_params) return await uyusmazlik_client_instance.search_decisions(search_params)
except Exception as e: except Exception as e:
@@ -229,16 +400,90 @@ async def get_uyusmazlik_document_markdown_from_url(document_url: HttpUrl) -> Uy
raise raise
# --- MCP Tools for Anayasa Mahkemesi (Norm Denetimi) --- # --- MCP Tools for Anayasa Mahkemesi (Norm Denetimi) ---
# ... (Anayasa Norm araçları öncekiyle aynı, docstringler İngilizce) ...
@app.tool() @app.tool()
async def search_anayasa_norm_denetimi_decisions( async def search_anayasa_norm_denetimi_decisions(
search_query: AnayasaNormDenetimiSearchRequest keywords_all: List[str] = Field(default_factory=list, description="Keywords for AND logic."),
keywords_any: List[str] = Field(default_factory=list, description="Keywords for OR logic."),
keywords_exclude: List[str] = Field(default_factory=list, description="Keywords to exclude."),
period: Literal["", "1", "2"] = Field("", description="Constitutional period ('': All, '1': 1961, '2': 1982)."),
case_number_esas: Optional[str] = Field(None, description="Case registry number (e.g., '2023/123')."),
decision_number_karar: Optional[str] = Field(None, description="Decision number (e.g., '2023/456')."),
first_review_date_start: Optional[str] = Field(None, description="First review start date (DD/MM/YYYY)."),
first_review_date_end: Optional[str] = Field(None, description="First review end date (DD/MM/YYYY)."),
decision_date_start: Optional[str] = Field(None, description="Decision start date (DD/MM/YYYY)."),
decision_date_end: Optional[str] = Field(None, description="Decision end date (DD/MM/YYYY)."),
application_type: Literal["", "1", "2", "3"] = Field("", description="Application type ('': All, '1': İptal, '2': İtiraz, '3': Diğer)."),
applicant_general_name: Optional[str] = Field(None, description="General applicant name."),
applicant_specific_name: Optional[str] = Field(None, description="Specific applicant name."),
official_gazette_date_start: Optional[str] = Field(None, description="Official Gazette start date (DD/MM/YYYY)."),
official_gazette_date_end: Optional[str] = Field(None, description="Official Gazette end date (DD/MM/YYYY)."),
official_gazette_number_start: Optional[str] = Field(None, description="Official Gazette starting number."),
official_gazette_number_end: Optional[str] = Field(None, description="Official Gazette ending number."),
has_press_release: Literal["", "0", "1"] = Field("", description="Press release ('': All, '0': No, '1': Yes)."),
has_dissenting_opinion: Literal["", "0", "1"] = Field("", description="Dissenting opinion ('': All, '0': No, '1': Yes)."),
has_different_reasoning: Literal["", "0", "1"] = Field("", description="Different reasoning ('': All, '0': No, '1': Yes)."),
attending_members_names: List[str] = Field(default_factory=list, description="List of attending members' exact names."),
rapporteur_name: Optional[str] = Field(None, description="Rapporteur's exact name."),
norm_type: Literal["", "1", "2", "14", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "0", "13"] = Field("", description="Type of reviewed norm."),
norm_id_or_name: Optional[str] = Field(None, description="Number or name of the norm."),
norm_article: Optional[str] = Field(None, description="Article number of the norm."),
review_outcomes: List[Literal["", "1", "2", "3", "4", "5", "6", "7", "8", "12"]] = Field(default_factory=list, description="List of review outcomes."),
reason_for_final_outcome: Literal["", "29", "1", "2", "30", "3", "4", "27", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26"] = Field("", description="Main reason for decision outcome."),
basis_constitution_article_numbers: List[str] = Field(default_factory=list, description="List of supporting Constitution article numbers."),
results_per_page: int = Field(10, description="Results per page (10, 20, 30, 40, 50)."),
page_to_fetch: int = Field(1, ge=1, description="Page number to fetch."),
sort_by_criteria: str = Field("KararTarihi", description="Sort criteria ('KararTarihi', 'YayinTarihi', 'Toplam').")
) -> AnayasaSearchResult: ) -> AnayasaSearchResult:
""" """
Searches Anayasa Mahkemesi (Constitutional Court) Norm Denetimi (Norm Control) decisions Searches Anayasa Mahkemesi (Constitutional Court) Norm Denetimi (Norm Control) decisions
using criteria from https://normkararlarbilgibankasi.anayasa.gov.tr. using criteria from https://normkararlarbilgibankasi.anayasa.gov.tr.
""" """
logger.info(f"Tool 'search_anayasa_norm_denetimi_decisions' called.") # Query loglaması kaldırıldı
# Convert string literals to enums
period_enum = AnayasaDonemEnum(period)
application_type_enum = AnayasaBasvuruTuruEnum(application_type)
has_press_release_enum = AnayasaVarYokEnum(has_press_release)
has_dissenting_opinion_enum = AnayasaVarYokEnum(has_dissenting_opinion)
has_different_reasoning_enum = AnayasaVarYokEnum(has_different_reasoning)
norm_type_enum = AnayasaNormTuruEnum(norm_type)
review_outcomes_enums = [AnayasaIncelemeSonucuEnum(ro) for ro in review_outcomes]
reason_for_final_outcome_enum = AnayasaSonucGerekcesiEnum(reason_for_final_outcome)
search_query = AnayasaNormDenetimiSearchRequest(
keywords_all=keywords_all,
keywords_any=keywords_any,
keywords_exclude=keywords_exclude,
period=period_enum,
case_number_esas=case_number_esas,
decision_number_karar=decision_number_karar,
first_review_date_start=first_review_date_start,
first_review_date_end=first_review_date_end,
decision_date_start=decision_date_start,
decision_date_end=decision_date_end,
application_type=application_type_enum,
applicant_general_name=applicant_general_name,
applicant_specific_name=applicant_specific_name,
official_gazette_date_start=official_gazette_date_start,
official_gazette_date_end=official_gazette_date_end,
official_gazette_number_start=official_gazette_number_start,
official_gazette_number_end=official_gazette_number_end,
has_press_release=has_press_release_enum,
has_dissenting_opinion=has_dissenting_opinion_enum,
has_different_reasoning=has_different_reasoning_enum,
attending_members_names=attending_members_names,
rapporteur_name=rapporteur_name,
norm_type=norm_type_enum,
norm_id_or_name=norm_id_or_name,
norm_article=norm_article,
review_outcomes=review_outcomes_enums,
reason_for_final_outcome=reason_for_final_outcome_enum,
basis_constitution_article_numbers=basis_constitution_article_numbers,
results_per_page=results_per_page,
page_to_fetch=page_to_fetch,
sort_by_criteria=sort_by_criteria
)
logger.info(f"Tool 'search_anayasa_norm_denetimi_decisions' called.")
try: try:
return await anayasa_norm_client_instance.search_norm_denetimi_decisions(search_query) return await anayasa_norm_client_instance.search_norm_denetimi_decisions(search_query)
except Exception as e: except Exception as e:
@@ -266,17 +511,23 @@ async def get_anayasa_norm_denetimi_document_markdown(
raise raise
# --- MCP Tools for Anayasa Mahkemesi (Bireysel Başvuru Karar Raporu & Belgeler) --- # --- MCP Tools for Anayasa Mahkemesi (Bireysel Başvuru Karar Raporu & Belgeler) ---
# ... (Anayasa Bireysel araçları öncekiyle aynı, docstringler İngilizce) ...
@app.tool() @app.tool()
async def search_anayasa_bireysel_basvuru_report( async def search_anayasa_bireysel_basvuru_report(
search_query: AnayasaBireyselReportSearchRequest keywords: List[str] = Field(default_factory=list, description="Keywords for AND logic."),
page_to_fetch: int = Field(1, ge=1, description="Page number to fetch for the report. Default is 1.")
) -> AnayasaBireyselReportSearchResult: ) -> AnayasaBireyselReportSearchResult:
""" """
Searches Anayasa Mahkemesi (Constitutional Court) Bireysel Başvuru (Individual Application) Searches Anayasa Mahkemesi (Constitutional Court) Bireysel Başvuru (Individual Application)
decisions and generates a 'Karar Arama Raporu' (Decision Search Report). decisions and generates a 'Karar Arama Raporu' (Decision Search Report).
This is for https://kararlarbilgibankasi.anayasa.gov.tr (uses KararBulteni=1). This is for https://kararlarbilgibankasi.anayasa.gov.tr (uses KararBulteni=1).
""" """
logger.info(f"Tool 'search_anayasa_bireysel_basvuru_report' called.") # Query loglaması kaldırıldı
search_query = AnayasaBireyselReportSearchRequest(
keywords=keywords,
page_to_fetch=page_to_fetch
)
logger.info(f"Tool 'search_anayasa_bireysel_basvuru_report' called.")
try: try:
return await anayasa_bireysel_client_instance.search_bireysel_basvuru_report(search_query) return await anayasa_bireysel_client_instance.search_bireysel_basvuru_report(search_query)
except Exception as e: except Exception as e:
@@ -305,16 +556,48 @@ async def get_anayasa_bireysel_basvuru_document_markdown(
# --- MCP Tools for KIK (Kamu İhale Kurulu) --- # --- MCP Tools for KIK (Kamu İhale Kurulu) ---
@app.tool() @app.tool()
async def search_kik_decisions(search_query: KikSearchRequest) -> KikSearchResult: async def search_kik_decisions(
karar_tipi: Literal["rbUyusmazlik", "rbDuzenleyici", "rbMahkeme"] = Field("rbUyusmazlik", description="Type of KIK Decision."),
karar_no: Optional[str] = Field(None, description="Decision Number (e.g., '2024/UH.II-1766')."),
karar_tarihi_baslangic: Optional[str] = Field(None, description="Decision Date Start (DD.MM.YYYY)."),
karar_tarihi_bitis: Optional[str] = Field(None, description="Decision Date End (DD.MM.YYYY)."),
basvuru_sahibi: Optional[str] = Field(None, description="Applicant."),
ihaleyi_yapan_idare: Optional[str] = Field(None, description="Procuring Entity."),
basvuru_konusu_ihale: Optional[str] = Field(None, description="Tender subject of the application."),
karar_metni: Optional[str] = Field(None, description="Keyword/phrase in decision text."),
yil: Optional[str] = Field(None, description="Year of the decision."),
resmi_gazete_tarihi: Optional[str] = Field(None, description="Official Gazette Date (DD.MM.YYYY)."),
resmi_gazete_sayisi: Optional[str] = Field(None, description="Official Gazette Number."),
page: int = Field(1, ge=1, description="Results page number.")
) -> KikSearchResult:
""" """
Searches KIK (Public Procurement Authority) decisions. Searches KIK (Public Procurement Authority) decisions.
""" """
logger.info(f"Tool 'search_kik_decisions' called.") # Query loglaması kaldırıldı
# Convert string literal to enum
karar_tipi_enum = KikKararTipi(karar_tipi)
search_query = KikSearchRequest(
karar_tipi=karar_tipi_enum,
karar_no=karar_no,
karar_tarihi_baslangic=karar_tarihi_baslangic,
karar_tarihi_bitis=karar_tarihi_bitis,
basvuru_sahibi=basvuru_sahibi,
ihaleyi_yapan_idare=ihaleyi_yapan_idare,
basvuru_konusu_ihale=basvuru_konusu_ihale,
karar_metni=karar_metni,
yil=yil,
resmi_gazete_tarihi=resmi_gazete_tarihi,
resmi_gazete_sayisi=resmi_gazete_sayisi,
page=page
)
logger.info(f"Tool 'search_kik_decisions' called.")
try: try:
api_response = await kik_client_instance.search_decisions(search_query) api_response = await kik_client_instance.search_decisions(search_query)
page_param_for_log = search_query.page if hasattr(search_query, 'page') else 1 page_param_for_log = search_query.page if hasattr(search_query, 'page') else 1
if not api_response.decisions and api_response.total_records == 0 and page_param_for_log == 1: if not api_response.decisions and api_response.total_records == 0 and page_param_for_log == 1:
logger.warning(f"KIK search returned no decisions for query.") # Query detayı kaldırıldı logger.warning(f"KIK search returned no decisions for query.")
return api_response return api_response
except Exception as e: except Exception as e:
logger.exception(f"Error in KIK search tool 'search_kik_decisions'.") logger.exception(f"Error in KIK search tool 'search_kik_decisions'.")
@@ -360,7 +643,6 @@ async def get_kik_document_markdown(
) )
# --- Application Shutdown Handling --- # --- Application Shutdown Handling ---
# ... (perform_cleanup ve main fonksiyonları öncekiyle aynı, değişiklik yok) ...
def perform_cleanup(): def perform_cleanup():
logger.info("MCP Server performing cleanup...") logger.info("MCP Server performing cleanup...")
try: try:
@@ -404,7 +686,9 @@ def perform_cleanup():
except Exception as e: except Exception as e:
logger.error(f"Error during atexit cleanup execution: {e}", exc_info=True) logger.error(f"Error during atexit cleanup execution: {e}", exc_info=True)
logger.info("MCP Server atexit cleanup process finished.") logger.info("MCP Server atexit cleanup process finished.")
atexit.register(perform_cleanup) atexit.register(perform_cleanup)
def main(): def main():
logger.info(f"Starting {app.name} server via main() function...") logger.info(f"Starting {app.name} server via main() function...")
logger.info(f"Logs will be written to: {LOG_FILE_PATH}") logger.info(f"Logs will be written to: {LOG_FILE_PATH}")
@@ -416,5 +700,6 @@ def main():
logger.exception("Server failed to start or crashed.") logger.exception("Server failed to start or crashed.")
finally: finally:
logger.info(f"{app.name} server has shut down.") logger.info(f"{app.name} server has shut down.")
if __name__ == "__main__": if __name__ == "__main__":
main() main()
+1 -1
View File
@@ -6,12 +6,12 @@ readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [
"beautifulsoup4>=4.13.4", "beautifulsoup4>=4.13.4",
"fastmcp>=2.2.10",
"httpx>=0.28.1", "httpx>=0.28.1",
"markitdown>=0.1.1", "markitdown>=0.1.1",
"pydantic>=2.11.4", "pydantic>=2.11.4",
"aiohttp>=3.11.18", "aiohttp>=3.11.18",
"playwright>=1.52.0", "playwright>=1.52.0",
"fastmcp>=2.5.1",
] ]
[project.scripts] [project.scripts]
+1 -1
View File
@@ -196,7 +196,7 @@ class UyusmazlikApiClient:
markdown_text = None markdown_text = None
temp_file_path = None temp_file_path = None
try: try:
md_converter = MarkItDown(enable_plugins=False) md_converter = MarkItDown()
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_file:
tmp_file.write(html_input_for_markdown) tmp_file.write(html_input_for_markdown)
temp_file_path = tmp_file.name temp_file_path = tmp_file.name
+1 -1
View File
@@ -110,7 +110,7 @@ class YargitayOfficialApiClient:
markdown_output = None markdown_output = None
temp_file_path = None temp_file_path = None
try: try:
md_converter = MarkItDown(enable_plugins=False) # Plugins disabled as per basic usage md_converter = MarkItDown() # Plugins disabled as per basic usage
# Write the HTML to a temporary file for MarkItDown to process # Write the HTML to a temporary file for MarkItDown to process
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_html_file: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".html", encoding="utf-8") as tmp_html_file: