Skip to main content
Glama
saidsurucu

Mevzuat MCP

by saidsurucu

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:

  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")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
mevzuat_noYesThe communiqué number from search results (e.g., '42331')
mevzuat_tertipNoCommuniqué series from search results (e.g., '5')5

Implementation Reference

  • 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)}"
            )
  • 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
  • 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}"
        )
  • The @app.tool() decorator registers the get_teblig_content function as an MCP tool.
    @app.tool()
  • 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",

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/saidsurucu/mevzuat-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server