Skip to main content
Glama
saidsurucu

Mevzuat MCP

by saidsurucu

get_cbgenelge_content

Retrieve and convert Turkish Presidential Circulars from PDF to Markdown format for analysis, summarization, or question answering.

Instructions

Retrieve the full content of a Turkish Presidential Circular (Cumhurbaşkanlığı Genelgesi) in Markdown format.

This tool fetches the PDF document and converts it to Markdown. Presidential Circulars are available only as PDF files. Use 'search_cbgenelge' first to find the circular number and Official Gazette date.

IMPORTANT: You must provide the 'resmi_gazete_tarihi' (Official Gazette date) from the search results. This is required to construct the correct PDF URL.

Returns:

  • Full circular content formatted as Markdown (converted from PDF)

  • Ready for analysis, summarization, or question answering

Example usage:

  1. Search for circulars: search_cbgenelge(baslangic_tarihi="2025")

  2. Get full content: get_cbgenelge_content(mevzuat_no="16", resmi_gazete_tarihi="20/09/2025", mevzuat_tertip="5")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
mevzuat_noYesThe Presidential Circular number from search results (e.g., '16', '15')
resmi_gazete_tarihiYesOfficial Gazette date from search results in DD/MM/YYYY format (e.g., '20/09/2025')
mevzuat_tertipNoCircular series from search results (e.g., '5')5

Implementation Reference

  • The handler and registration for the 'get_cbgenelge_content' MCP tool using FastMCP @app.tool() decorator. Defines input schema via Pydantic Field descriptions, logs parameters, delegates to MevzuatApiClientNew.get_content with mevzuat_tur=22, handles errors, and returns MevzuatArticleContent.
    @app.tool()
    async def get_cbgenelge_content(
        mevzuat_no: str = Field(
            ...,
            description="The Presidential Circular number from search results (e.g., '16', '15')"
        ),
        resmi_gazete_tarihi: str = Field(
            ...,
            description="Official Gazette date from search results in DD/MM/YYYY format (e.g., '20/09/2025')"
        ),
        mevzuat_tertip: str = Field(
            "5",
            description="Circular series from search results (e.g., '5')"
        )
    ) -> MevzuatArticleContent:
        """
        Retrieve the full content of a Turkish Presidential Circular (Cumhurbaşkanlığı Genelgesi) in Markdown format.
    
        This tool fetches the PDF document and converts it to Markdown.
        Presidential Circulars are available only as PDF files.
        Use 'search_cbgenelge' first to find the circular number and Official Gazette date.
    
        IMPORTANT: You must provide the 'resmi_gazete_tarihi' (Official Gazette date) from the search results.
        This is required to construct the correct PDF URL.
    
        Returns:
        - Full circular content formatted as Markdown (converted from PDF)
        - Ready for analysis, summarization, or question answering
    
        Example usage:
        1. Search for circulars: search_cbgenelge(baslangic_tarihi="2025")
        2. Get full content: get_cbgenelge_content(mevzuat_no="16", resmi_gazete_tarihi="20/09/2025", mevzuat_tertip="5")
        """
        logger.info(f"Tool 'get_cbgenelge_content' called: {mevzuat_no}, RG date: {resmi_gazete_tarihi}, tertip: {mevzuat_tertip}")
    
        try:
            result = await mevzuat_client.get_content(
                mevzuat_no=mevzuat_no,
                mevzuat_tur=22,  # Cumhurbaşkanlığı Genelgesi
                mevzuat_tertip=mevzuat_tertip,
                resmi_gazete_tarihi=resmi_gazete_tarihi
            )
    
            if result.error_message:
                logger.warning(f"Error fetching circular content: {result.error_message}")
    
            return result
    
        except Exception as e:
            logger.exception(f"Error in tool 'get_cbgenelge_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)}"
            )
  • Core helper function MevzuatApiClientNew.get_content that implements the PDF download and markdown conversion for CB Genelgesi (tur=22). Constructs special PDF URL using formatted resmi_gazete_tarihi, downloads PDF, optionally uses Mistral OCR for text extraction from images, falls back to markitdown PDF conversion, supports caching.
    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}"
        )
  • Pydantic schema model MevzuatArticleContent returned by the tool, containing the extracted markdown_content of the Presidential Circular and optional error_message.
    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

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