search_teblig
Search Turkish regulatory communiqués (Tebliğ) by title and content to find government-issued documents using keywords, Boolean operators, and date filters.
Instructions
Search for Turkish communiqués (Tebliğ) in both titles and content.
This tool searches in communiqué titles and full text content. Communiqués are regulatory documents issued by various government institutions.
Query Syntax:
Simple keyword: vergi
Boolean AND: vergi AND muafiyet (both terms)
Boolean OR: muafiyet OR istisna (at least one term)
Boolean NOT: vergi NOT gelir (first yes, second no)
Required term: +vergi +muafiyet (similar to AND)
Grouping: (muafiyet OR istisna) AND vergi
Exact phrase: "katma değer vergisi" (or use tam_cumle=true)
Returns:
Communiqué number, title, and publication date
Official Gazette publication date and issue number
URLs for viewing online
Example queries:
"katma değer vergisi" - Find VAT-related communiqués
"muafiyet OR istisna" - Communiqués about exemptions
"vergi AND matrah" - Tax base related communiqués
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| aranacak_ifade | Yes | Search query with optional Boolean operators: simple word (vergi), AND (vergi AND muafiyet), OR (muafiyet OR istisna), NOT (vergi NOT gelir), + for required (+term), grouping with (), exact phrase with quotes ("katma değer vergisi") | |
| tam_cumle | No | Exact phrase match (true) or any word match (false, default). Set to true when searching for exact phrases. | |
| baslangic_tarihi | No | Start year for filtering results (format: YYYY, e.g., '2020') | |
| bitis_tarihi | No | End year for filtering results (format: YYYY, e.g., '2024') | |
| page_number | No | Page number for pagination (starts at 1) | |
| page_size | No | Number of results per page (1-100) |
Implementation Reference
- mevzuat_mcp_server.py:224-311 (handler)The handler function implementing the 'search_teblig' MCP tool. It creates a search request specific to 'Tebliğ' (communiqués), calls the MevzuatApiClientNew.search_documents method, and handles errors, returning structured search results.async def search_teblig( aranacak_ifade: str = Field( ..., description='Search query with optional Boolean operators: simple word (vergi), AND (vergi AND muafiyet), OR (muafiyet OR istisna), NOT (vergi NOT gelir), + for required (+term), grouping with (), exact phrase with quotes ("katma değer vergisi")' ), tam_cumle: bool = Field( False, description="Exact phrase match (true) or any word match (false, default). Set to true when searching for exact phrases." ), baslangic_tarihi: Optional[str] = Field( None, description="Start year for filtering results (format: YYYY, e.g., '2020')" ), bitis_tarihi: Optional[str] = Field( None, description="End year for filtering results (format: YYYY, e.g., '2024')" ), page_number: int = Field( 1, ge=1, description="Page number for pagination (starts at 1)" ), page_size: int = Field( 25, ge=1, le=100, description="Number of results per page (1-100)" ) ) -> MevzuatSearchResultNew: """ Search for Turkish communiqués (Tebliğ) in both titles and content. This tool searches in communiqué titles and full text content. Communiqués are regulatory documents issued by various government institutions. Query Syntax: - Simple keyword: vergi - Boolean AND: vergi AND muafiyet (both terms) - Boolean OR: muafiyet OR istisna (at least one term) - Boolean NOT: vergi NOT gelir (first yes, second no) - Required term: +vergi +muafiyet (similar to AND) - Grouping: (muafiyet OR istisna) AND vergi - Exact phrase: "katma değer vergisi" (or use tam_cumle=true) Returns: - Communiqué number, title, and publication date - Official Gazette publication date and issue number - URLs for viewing online Example queries: - "katma değer vergisi" - Find VAT-related communiqués - "muafiyet OR istisna" - Communiqués about exemptions - "vergi AND matrah" - Tax base related communiqués """ search_req = MevzuatSearchRequestNew( mevzuat_tur="Tebliğ", aranacak_ifade=aranacak_ifade, aranacak_yer=1, # Search in titles and content tam_cumle=tam_cumle, mevzuat_no=None, baslangic_tarihi=baslangic_tarihi, bitis_tarihi=bitis_tarihi, page_number=page_number, page_size=page_size ) log_params = search_req.model_dump(exclude_defaults=True) logger.info(f"Tool 'search_teblig' called with parameters: {log_params}") try: result = await mevzuat_client.search_documents(search_req) if not result.documents and not result.error_message: result.error_message = "No communiqués found matching the specified criteria." return result except Exception as e: logger.exception("Error in tool 'search_teblig'") return MevzuatSearchResultNew( documents=[], total_results=0, current_page=page_number, page_size=page_size, total_pages=0, query_used=log_params, error_message=f"An unexpected error occurred: {str(e)}" )
- mevzuat_models.py:107-117 (schema)Pydantic model defining the output schema (MevzuatSearchResultNew) returned by the search_teblig tool.class MevzuatSearchResultNew(BaseModel): """Model for search results from mevzuat.gov.tr""" documents: List[MevzuatDocumentNew] total_results: int current_page: int page_size: int total_pages: int query_used: Dict[str, Any] error_message: Optional[str] = None
- mevzuat_models.py:32-84 (schema)Pydantic model (MevzuatSearchRequestNew) used as input structure for the search request in search_teblig handler.class MevzuatSearchRequestNew(BaseModel): """Request model for searching legislation on mevzuat.gov.tr""" mevzuat_tur: MevzuatTurLiteral = Field( "Kanun", description="Type of legislation. Currently only 'Kanun' (laws) are fully supported for content extraction." ) aranacak_ifade: Optional[str] = Field( None, description="Search term or phrase to look for in legislation" ) aranacak_yer: int = Field( 3, ge=1, le=3, description="Where to search: 1=Title only, 2=Article titles, 3=Full text (default)" ) tam_cumle: bool = Field( False, description="Exact phrase match (true) or any word match (false, default)" ) mevzuat_no: Optional[str] = Field( None, description="Specific legislation number to search for" ) baslangic_tarihi: Optional[str] = Field( None, description="Start date for filtering (format: DD.MM.YYYY)" ) bitis_tarihi: Optional[str] = Field( None, description="End date for filtering (format: DD.MM.YYYY)" ) page_number: int = Field( 1, ge=1, description="Page number of results" ) page_size: int = Field( 10, ge=1, le=100, description="Number of results per page" )
- mevzuat_mcp_server.py:29-224 (registration)The FastMCP app instantiation and @app.tool() decorator register the search_teblig function as an MCP tool.app = FastMCP( name="MevzuatGovTrMCP", instructions="MCP server for mevzuat.gov.tr. Allows searching Turkish legislation (Kanun/laws, Tebliğ/communiqués, CB Kararnamesi/Presidential Decrees, CB Kararı/Presidential Decisions, CB Yönetmeliği/Presidential Regulations, CB Genelgesi/Presidential Circulars) and retrieving full content." ) # Initialize client with caching enabled (1 hour TTL by default) # Mistral API key will be loaded from environment variable MISTRAL_API_KEY mevzuat_client = MevzuatApiClientNew(cache_ttl=3600, enable_cache=True) @app.tool() async def search_kanun( aranacak_ifade: str = Field( ..., description='Search query with optional Boolean operators: simple word (yatırımcı), AND (yatırımcı AND tazmin), OR (vergi OR ücret), NOT (yatırımcı NOT kurum), + for required (+term), grouping with (), exact phrase with quotes ("mali sıkıntı")' ), tam_cumle: bool = Field( False, description="Exact phrase match (true) or any word match (false, default). Set to true when searching for exact phrases like 'mali sıkıntı'." ), baslangic_tarihi: Optional[str] = Field( None, description="Start date for filtering results (format: DD.MM.YYYY, e.g., '01.01.2020')" ), bitis_tarihi: Optional[str] = Field( None, description="End date for filtering results (format: DD.MM.YYYY, e.g., '31.12.2024')" ), page_number: int = Field( 1, ge=1, description="Page number for pagination (starts at 1)" ), page_size: int = Field( 25, ge=1, le=100, description="Number of results per page (1-100)" ) ) -> MevzuatSearchResultNew: """ Search for Turkish laws (Kanun) in both titles and content. This tool searches in law titles and full text content. Use 'search_within_kanun' to search within a specific law's articles and get article-level results. Query Syntax: - Simple keyword: yatırımcı - Boolean AND: yatırımcı AND tazmin (both terms) - Boolean OR: yatırımcı OR müşteri (at least one term) - Boolean NOT: yatırımcı NOT kurum (first yes, second no) - Required term: +yatırımcı +tazmin (similar to AND) - Grouping: (yatırımcı OR müşteri) AND tazmin - Exact phrase: "mali sıkıntı" (or use tam_cumle=true) Returns: - Law number, title, and acceptance date - Official Gazette publication date and issue number - URLs for viewing online and downloading PDF Example queries: - "sermaye piyasası" - Find Capital Markets Law - "vergi OR gelir" - Laws with tax or income in title/content - "ceza muhakemesi" - Find Criminal Procedure Law """ search_req = MevzuatSearchRequestNew( mevzuat_tur="Kanun", aranacak_ifade=aranacak_ifade, aranacak_yer=1, # 1=Title only tam_cumle=tam_cumle, mevzuat_no=None, baslangic_tarihi=baslangic_tarihi, bitis_tarihi=bitis_tarihi, page_number=page_number, page_size=page_size ) log_params = search_req.model_dump(exclude_defaults=True) logger.info(f"Tool 'search_kanun' called with parameters: {log_params}") try: result = await mevzuat_client.search_documents(search_req) if not result.documents and not result.error_message: result.error_message = "No legislation found matching the specified criteria." return result except Exception as e: logger.exception("Error in tool 'search_mevzuat'") return MevzuatSearchResultNew( documents=[], total_results=0, current_page=page_number, page_size=page_size, total_pages=0, query_used=log_params, error_message=f"An unexpected error occurred: {str(e)}" ) @app.tool() async def search_within_kanun( mevzuat_no: str = Field( ..., description="The legislation number to search within (e.g., '6362', '5237')" ), keyword: str = Field( ..., description='Search query supporting advanced operators: simple keyword ("yatırımcı"), exact phrase ("mali sıkıntı"), AND/OR/NOT operators (yatırımcı AND tazmin, yatırımcı OR müşteri, yatırımcı NOT kurum). Operators must be uppercase.' ), mevzuat_tertip: str = Field( "5", description="Legislation series from search results (e.g., '3', '5')" ), case_sensitive: bool = Field( False, description="Whether to match case when searching (default: False)" ), max_results: int = Field( 25, ge=1, le=50, description="Maximum number of matching articles to return (1-50, default: 25)" ) ) -> str: """ Search for a keyword within a specific legislation's articles with advanced query operators. This tool is optimized for large legislation (e.g., Sermaye Piyasası Kanunu with 142 articles). Instead of loading the entire legislation into context, it: 1. Fetches the full content 2. Splits it into individual articles (madde) 3. Returns only the articles that match the search query 4. Sorts results by relevance score (based on match count) Query Syntax (operators must be uppercase): - Simple keyword: yatırımcı - Exact phrase: "mali sıkıntı" - AND operator: yatırımcı AND tazmin (both terms must be present) - OR operator: yatırımcı OR müşteri (at least one term must be present) - NOT operator: yatırımcı NOT kurum (first term present, second must not be) - Combinations: "mali sıkıntı" AND yatırımcı NOT kurum Returns formatted text with: - Article number and title - Relevance score (higher = more matches) - Full article content for matching articles Example use cases: - Search for "yatırımcı" in Kanun 6362 (Capital Markets Law) - Search for "ceza AND temyiz" in Kanun 5237 (Turkish Penal Code) - Search for "vergi OR ücret" in tax-related legislation - Search for '"iş kazası" AND işveren NOT işçi' for specific labor law articles """ logger.info(f"Tool 'search_within_kanun' called: {mevzuat_no}, keyword: '{keyword}'") try: # Get full content content_result = await mevzuat_client.get_content( mevzuat_no=mevzuat_no, mevzuat_tur=1, # Kanun mevzuat_tertip=mevzuat_tertip ) if content_result.error_message: return f"Error fetching legislation content: {content_result.error_message}" # Search within articles matches = search_articles_by_keyword( markdown_content=content_result.markdown_content, keyword=keyword, case_sensitive=case_sensitive, max_results=max_results ) result = ArticleSearchResult( mevzuat_no=mevzuat_no, mevzuat_tur=1, keyword=keyword, total_matches=len(matches), matching_articles=matches ) if len(matches) == 0: return f"No articles found containing '{keyword}' in Kanun {mevzuat_no}" return format_search_results(result) except Exception as e: logger.exception(f"Error in tool 'search_within_kanun' for {mevzuat_no}") return f"An unexpected error occurred: {str(e)}" @app.tool() async def search_teblig(
- mevzuat_client.py:451-556 (helper)The underlying search_documents method in MevzuatApiClientNew class that performs the actual API search call used by search_teblig.async def search_documents(self, request: MevzuatSearchRequestNew) -> MevzuatSearchResultNew: """Search for legislation documents using httpx with Playwright cookies.""" # Get session/cookies with Playwright first await self._ensure_session() # If session establishment failed, fallback to full Playwright method if not self._antiforgery_token and not self._cookies: logger.warning("Session establishment failed, using full Playwright search method as fallback") return await self.search_documents_with_playwright(request) # Build DataTables compatible payload # Normalize mevzuat type for API mevzuat_tur_api = self._normalize_mevzuat_tur_for_api(request.mevzuat_tur) payload = { "draw": 1, "columns": [ {"data": None, "name": "", "searchable": True, "orderable": False, "search": {"value": "", "regex": False}}, {"data": None, "name": "", "searchable": True, "orderable": False, "search": {"value": "", "regex": False}}, {"data": None, "name": "", "searchable": True, "orderable": False, "search": {"value": "", "regex": False}} ], "order": [], "start": (request.page_number - 1) * request.page_size, "length": request.page_size, "search": {"value": "", "regex": False}, "parameters": { "MevzuatTur": mevzuat_tur_api, "YonetmelikMevzuatTur": "OsmanliKanunu", # Required for all searches "AranacakIfade": request.aranacak_ifade or "", "TamCumle": "true" if request.tam_cumle else "false", "AranacakYer": str(request.aranacak_yer), "MevzuatNo": request.mevzuat_no or "", "KurumId": "0", "AltKurumId": "0", "BaslangicTarihi": request.baslangic_tarihi or "", "BitisTarihi": request.bitis_tarihi or "", "antiforgerytoken": self._antiforgery_token or "" } } try: # Log payload for debugging logger.debug(f"Search payload: {payload}") # Make request with cookies properly response = await self._http_client.post( self.SEARCH_ENDPOINT, json=payload, cookies=self._cookies if self._cookies else None ) # Log response for debugging if response.status_code != 200: logger.error(f"Search API error {response.status_code}: {response.text[:500]}") response.raise_for_status() data = response.json() total_results = data.get("recordsTotal", 0) documents = [] for item in data.get("data", []): doc = MevzuatDocumentNew( mevzuat_no=item.get("mevzuatNo", ""), mev_adi=item.get("mevAdi", ""), kabul_tarih=item.get("kabulTarih", ""), resmi_gazete_tarihi=item.get("resmiGazeteTarihi", ""), resmi_gazete_sayisi=item.get("resmiGazeteSayisi", ""), mevzuat_tertip=item.get("mevzuatTertip", ""), mevzuat_tur=item.get("tur", 1), url=item.get("url", "") ) documents.append(doc) return MevzuatSearchResultNew( documents=documents, total_results=total_results, current_page=request.page_number, page_size=request.page_size, total_pages=(total_results + request.page_size - 1) // request.page_size if request.page_size > 0 else 0, query_used=request.model_dump() ) except httpx.HTTPStatusError as e: logger.error(f"Search request failed: {e.response.status_code}") return MevzuatSearchResultNew( documents=[], total_results=0, current_page=request.page_number, page_size=request.page_size, total_pages=0, query_used=request.model_dump(), error_message=f"API request failed: {e.response.status_code}" ) except Exception as e: logger.exception("Unexpected error during search") return MevzuatSearchResultNew( documents=[], total_results=0, current_page=request.page_number, page_size=request.page_size, total_pages=0, query_used=request.model_dump(), error_message=f"An unexpected error occurred: {e}" )