get_teblig_content
Retrieve the full Markdown content of a Turkish communiqué (Tebliğ) using its number and series for analysis, summarization, or question answering.
Instructions
Retrieve the full content of a Turkish communiqué (Tebliğ) in Markdown format.
This tool fetches the complete text of a communiqué identified by its number. Use 'search_teblig' first to find the communiqué number and series.
Returns:
Full communiqué content formatted as Markdown
Ready for analysis, summarization, or question answering
Example usage:
Search for communiqués: search_teblig(aranacak_ifade="katma değer vergisi")
Get full content: get_teblig_content(mevzuat_no="42331", mevzuat_tertip="5")
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mevzuat_no | Yes | The communiqué number from search results (e.g., '42331') | |
| mevzuat_tertip | No | Communiqué series from search results (e.g., '5') | 5 |
Implementation Reference
- mevzuat_mcp_server.py:314-361 (handler)The handler function for 'get_teblig_content' tool. Decorated with @app.tool() for MCP registration. Calls MevzuatApiClientNew.get_content with mevzuat_tur=9 specifically for Tebliğ documents.@app.tool() async def get_teblig_content( mevzuat_no: str = Field( ..., description="The communiqué number from search results (e.g., '42331')" ), mevzuat_tertip: str = Field( "5", description="Communiqué series from search results (e.g., '5')" ) ) -> MevzuatArticleContent: """ Retrieve the full content of a Turkish communiqué (Tebliğ) in Markdown format. This tool fetches the complete text of a communiqué identified by its number. Use 'search_teblig' first to find the communiqué number and series. Returns: - Full communiqué content formatted as Markdown - Ready for analysis, summarization, or question answering Example usage: 1. Search for communiqués: search_teblig(aranacak_ifade="katma değer vergisi") 2. Get full content: get_teblig_content(mevzuat_no="42331", mevzuat_tertip="5") """ logger.info(f"Tool 'get_teblig_content' called: {mevzuat_no}, tertip: {mevzuat_tertip}") try: result = await mevzuat_client.get_content( mevzuat_no=mevzuat_no, mevzuat_tur=9, # Tebliğ mevzuat_tertip=mevzuat_tertip ) if result.error_message: logger.warning(f"Error fetching communiqué content: {result.error_message}") return result except Exception as e: logger.exception(f"Error in tool 'get_teblig_content' for {mevzuat_no}") return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content="", error_message=f"An unexpected error occurred: {str(e)}" )
- mevzuat_models.py:119-125 (schema)Pydantic model defining the output schema (MevzuatArticleContent) returned by the tool.class MevzuatArticleContent(BaseModel): """Model for the content of legislation (reused from old models).""" madde_id: str mevzuat_id: str markdown_content: str error_message: Optional[str] = None
- mevzuat_client.py:557-724 (helper)The supporting method in MevzuatApiClientNew that performs the actual content fetching, conversion to markdown, and caching. Called by the tool with mevzuat_tur=9 for Tebliğ.async def get_content( self, mevzuat_no: str, mevzuat_tur: int = 1, mevzuat_tertip: str = "3", resmi_gazete_tarihi: Optional[str] = None ) -> MevzuatArticleContent: """ Download and extract content from legislation. Tries HTML scraping first (most reliable), then falls back to file downloads. For Presidential Decisions (tur=20) and Circulars (tur=22), skip HTML and go directly to PDF. Args: mevzuat_no: Legislation number mevzuat_tur: Legislation type code (1=Kanun, 20=CB Kararı, 22=CB Genelgesi, etc.) mevzuat_tertip: Series number resmi_gazete_tarihi: Official Gazette date (DD/MM/YYYY) - required for CB Genelgesi (tur=22) """ # CB Kararları (tur=20) and CB Genelgesi (tur=22) are PDF-only, skip HTML scraping if mevzuat_tur not in [20, 22]: # Try HTML scraping first (most reliable method for other types) result = await self.get_content_from_html(mevzuat_no, mevzuat_tur, mevzuat_tertip) if result.markdown_content: return result logger.info(f"HTML scraping returned no content for {mevzuat_no}, trying file downloads") else: if mevzuat_tur == 20: logger.info("CB Kararı detected (tur=20), skipping HTML scraping, going directly to PDF") elif mevzuat_tur == 22: logger.info("CB Genelgesi detected (tur=22), skipping HTML scraping, going directly to PDF") cache_key = f"doc:{mevzuat_tur}.{mevzuat_tertip}.{mevzuat_no}" if self._cache_enabled else None if cache_key and self._cache: cached_content = self._cache.get(cache_key) if cached_content: logger.debug(f"Cache hit: {mevzuat_no}") return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content=cached_content ) # Construct URLs based on mevzuat type if mevzuat_tur == 22: # CB Genelgesi - special PDF URL format if not resmi_gazete_tarihi: return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content="", error_message="resmi_gazete_tarihi is required for CB Genelgesi (tur=22)" ) # Convert DD/MM/YYYY to YYYYMMDD parts = resmi_gazete_tarihi.split('/') if len(parts) == 3: date_str = f"{parts[2]}{parts[1].zfill(2)}{parts[0].zfill(2)}" else: return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content="", error_message=f"Invalid date format: {resmi_gazete_tarihi}. Expected DD/MM/YYYY" ) pdf_url = self.GENELGE_PDF_URL_TEMPLATE.format(date=date_str, no=mevzuat_no) doc_url = None # Genelge has no DOC version elif mevzuat_tur == 20: # CB Kararı - PDF only, no DOC doc_url = None # CB Kararları have no DOC version pdf_url = self.PDF_URL_TEMPLATE.format(tur=mevzuat_tur, tertip=mevzuat_tertip, no=mevzuat_no) else: doc_url = self.DOC_URL_TEMPLATE.format(tur=mevzuat_tur, tertip=mevzuat_tertip, no=mevzuat_no) pdf_url = self.PDF_URL_TEMPLATE.format(tur=mevzuat_tur, tertip=mevzuat_tertip, no=mevzuat_no) # Try DOC first (skip for CB Genelgesi and CB Kararı which have no DOC version) if doc_url: try: logger.info(f"Trying DOC: {doc_url}") # Use separate headers for document download doc_headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36', 'Accept': 'application/msword, */*', } response = await self._http_client.get(doc_url, headers=doc_headers) response.raise_for_status() doc_bytes = response.content logger.info(f"Downloaded DOC: {len(doc_bytes)} bytes") # DOC files from mevzuat.gov.tr are actually HTML if len(doc_bytes) < 100: logger.warning(f"DOC file too small ({len(doc_bytes)} bytes), likely empty") raise Exception("DOC file is empty or too small") doc_stream = io.BytesIO(doc_bytes) result = self._md_converter.convert_stream(doc_stream, file_extension=".doc") markdown_content = result.text_content.strip() if result and result.text_content else "" if markdown_content: logger.info(f"DOC conversion successful for {mevzuat_no}") if cache_key and self._cache: self._cache.put(cache_key, markdown_content) return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content=markdown_content ) except Exception as e: logger.info(f"DOC failed, trying PDF: {e}") # Try PDF fallback try: logger.info(f"Trying PDF: {pdf_url}") # For CB Kararı (tur=20) and CB Genelgesi (tur=22), ensure we have session cookies if mevzuat_tur in [20, 22]: await self._ensure_session() # Create temporary client with cookies to avoid deprecation warning async with httpx.AsyncClient( headers=self.HEADERS, cookies=self._cookies, timeout=self._http_client.timeout, follow_redirects=True ) as temp_client: response = await temp_client.get(pdf_url) else: response = await self._http_client.get(pdf_url) response.raise_for_status() pdf_bytes = response.content markdown_content = "" # For CB Kararı (tur=20) and CB Genelgesi (tur=22), use Mistral OCR (handles images + text) if mevzuat_tur in [20, 22] and self._mistral_client: doc_type = "CB Kararı" if mevzuat_tur == 20 else "CB Genelgesi" logger.info(f"Using Mistral OCR for {doc_type} PDF") markdown_content = await self._ocr_pdf_with_mistral(pdf_bytes, pdf_url) # Fallback to markitdown if OCR fails if not markdown_content: logger.warning("Mistral OCR failed, falling back to markitdown") pdf_stream = io.BytesIO(pdf_bytes) result = self._md_converter.convert_stream(pdf_stream, file_extension=".pdf") markdown_content = result.text_content.strip() if result and result.text_content else "" else: # Use markitdown for other types pdf_stream = io.BytesIO(pdf_bytes) result = self._md_converter.convert_stream(pdf_stream, file_extension=".pdf") markdown_content = result.text_content.strip() if result and result.text_content else "" if markdown_content: logger.info(f"PDF conversion successful for {mevzuat_no}") if cache_key and self._cache: self._cache.put(cache_key, markdown_content) return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content=markdown_content ) except Exception as e: logger.error(f"PDF also failed: {e}") return MevzuatArticleContent( madde_id=mevzuat_no, mevzuat_id=mevzuat_no, markdown_content="", error_message=f"Both DOC and PDF download/conversion failed for {mevzuat_tur}.{mevzuat_tertip}.{mevzuat_no}" )
- mevzuat_mcp_server.py:314-314 (registration)The @app.tool() decorator registers the get_teblig_content function as an MCP tool.@app.tool()
- mevzuat_client.py:91-97 (helper)API mapping that normalizes 'Tebliğ' to 'Teblig' for search API requests.MEVZUAT_TUR_API_MAPPING = { "Kurum Yönetmeliği": "KurumVeKurulusYonetmeligi", "Cumhurbaşkanlığı Kararnamesi": "CumhurbaskaniKararnameleri", "Cumhurbaşkanı Kararı": "CumhurbaskaniKararlari", "CB Yönetmeliği": "CumhurbaskanligiVeBakanlarKuruluYonetmelik", "CB Genelgesi": "CumhurbaskanligiGenelgeleri", "Tebliğ": "Teblig",