Skip to main content
Glama
saidsurucu

Yargı MCP

by saidsurucu

get_kik_v2_document_markdown

Read-onlyIdempotent

Retrieve full text of Turkish Public Procurement Authority decisions in Markdown format using agenda item IDs from search results.

Instructions

Use this when retrieving full text of a KİK procurement decision. Returns document in Markdown format.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
gundemMaddesiIdYesgundemMaddesiId from search_kik_v2_decisions results

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main handler function of KikV2ApiClient class that implements the tool logic: fetches document URL via API, encrypts document ID if numeric, retrieves HTML content via httpx, converts to Markdown using MarkItDown, and returns KikV2DocumentMarkdown object.
    async def get_document_markdown(self, document_id: str) -> KikV2DocumentMarkdown:
        """
        Get KİK decision document content in Markdown format.
        
        This method uses a two-step process:
        1. Call GetSorgulamaUrl endpoint to get the actual document URL
        2. Use httpx to fetch the document content
        
        Args:
            document_id: The gundemMaddesiId from search results
            
        Returns:
            KikV2DocumentMarkdown with document content converted to Markdown
        """
        
        logger.info(f"KikV2ApiClient: Getting document for ID: {document_id}")
        
        if not document_id or not document_id.strip():
            return KikV2DocumentMarkdown(
                document_id=document_id,
                kararNo="",
                markdown_content="",
                source_url="",
                error_message="Document ID is required"
            )
        
        try:
            # Step 1: Get the actual document URL using GetSorgulamaUrl endpoint
            logger.info(f"KikV2ApiClient: Step 1 - Getting document URL for ID: {document_id}")
            
            # Update security headers for this request
            headers = {**self.http_client.headers, **self._generate_security_headers()}
            
            # Call GetSorgulamaUrl to get the real document URL
            url_payload = {"sorguSayfaTipi": 2}  # As shown in curl example
            
            url_response = await self.http_client.post(
                "/b_ihalearaclari/api/KurulKararlari/GetSorgulamaUrl",
                json=url_payload,
                headers=headers
            )
            
            url_response.raise_for_status()
            url_data = url_response.json()
            
            # Get the base document URL from API response
            base_document_url = url_data.get("sorgulamaUrl", "")
            if not base_document_url:
                return KikV2DocumentMarkdown(
                    document_id=document_id,
                    kararNo="",
                    markdown_content="",
                    source_url="",
                    error_message="Could not get document URL from GetSorgulamaUrl API"
                )
            
            # If document_id is numeric, encrypt it to get the KararId hash
            # The web interface uses AES-256-CBC encrypted hashes for document URLs
            karar_id = document_id
            if document_id.isdigit():
                try:
                    karar_id = self.encrypt_document_id(document_id)
                    logger.info(f"KikV2ApiClient: Encrypted numeric ID {document_id} to hash: {karar_id}")
                except Exception as enc_error:
                    logger.warning(f"KikV2ApiClient: Could not encrypt document ID, using as-is: {enc_error}")
    
            # Construct full document URL with the encrypted KararId
            document_url = f"{base_document_url}?KararId={karar_id}"
            logger.info(f"KikV2ApiClient: Step 2 - Retrieved document URL: {document_url}")
    
        except Exception as e:
            logger.error(f"KikV2ApiClient: Error getting document URL for ID {document_id}: {str(e)}")
            # Fallback to old method if GetSorgulamaUrl fails
            # Also encrypt numeric IDs in fallback path
            karar_id = document_id
            if document_id.isdigit():
                try:
                    karar_id = self.encrypt_document_id(document_id)
                    logger.info(f"KikV2ApiClient: Encrypted numeric ID in fallback: {karar_id}")
                except Exception as enc_error:
                    logger.warning(f"KikV2ApiClient: Could not encrypt in fallback: {enc_error}")
            document_url = f"https://ekap.kik.gov.tr/EKAP/Vatandas/KurulKararGoster.aspx?KararId={karar_id}"
            logger.info(f"KikV2ApiClient: Falling back to direct URL: {document_url}")
        
        try:
            # Step 2: Use httpx to get the document content
            logger.info(f"KikV2ApiClient: Step 2 - Using httpx to retrieve document from: {document_url}")
    
            # Create a separate httpx client for document retrieval with HTML headers
            doc_ssl_context = ssl.create_default_context()
            doc_ssl_context.check_hostname = False
            doc_ssl_context.verify_mode = ssl.CERT_NONE
            if hasattr(ssl, 'OP_LEGACY_SERVER_CONNECT'):
                doc_ssl_context.options |= ssl.OP_LEGACY_SERVER_CONNECT
            doc_ssl_context.set_ciphers('ALL:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA')
    
            async with httpx.AsyncClient(
                verify=doc_ssl_context,
                headers={
                    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                    "Accept-Language": "tr,en-US;q=0.5",
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
                },
                timeout=60.0,
                follow_redirects=True
            ) as doc_client:
                response = await doc_client.get(document_url)
                response.raise_for_status()
                html_content = response.text
                logger.info(f"KikV2ApiClient: Retrieved content via httpx, length: {len(html_content)}")
            
            # Convert HTML to Markdown using MarkItDown with BytesIO
            try:
                from markitdown import MarkItDown
                from io import BytesIO
                
                md = MarkItDown()
                html_bytes = html_content.encode('utf-8')
                html_stream = BytesIO(html_bytes)
                
                result = md.convert_stream(html_stream, file_extension=".html")
                markdown_content = result.text_content
                
                return KikV2DocumentMarkdown(
                    document_id=document_id,
                    kararNo="",
                    markdown_content=markdown_content,
                    source_url=document_url,
                    error_message=""
                )
                
            except ImportError:
                return KikV2DocumentMarkdown(
                    document_id=document_id,
                    kararNo="",
                    markdown_content="MarkItDown library not available",
                    source_url=document_url,
                    error_message="MarkItDown library not installed"
                )
                
        except Exception as e:
            logger.error(f"KikV2ApiClient: Error retrieving document {document_id}: {str(e)}")
            return KikV2DocumentMarkdown(
                document_id=document_id,
                kararNo="",
                markdown_content="",
                source_url=document_url,
                error_message=str(e)
            )
  • Pydantic BaseModel defining the input/output schema for the get_kik_v2_document_markdown tool response.
    class KikV2DocumentMarkdown(BaseModel):
        """Document content in Markdown format."""
        document_id: str = Field("", description="Document ID")
        kararNo: str = Field("", description="Decision number")
        markdown_content: str = Field("", description="Decision content in Markdown")
        source_url: str = Field("", description="Source URL")
        error_message: str = Field("", description="Error message if retrieval failed")
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, indicating safe, repeatable read operations. The description adds value by specifying the return format ('Markdown format') and the source context ('KİK procurement decision'), but does not provide additional behavioral details like rate limits, authentication needs, or error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the purpose and key details (use case, resource, output format) with zero wasted words, making it highly concise and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's low complexity (single required parameter), high schema coverage, presence of annotations, and an output schema (implied by 'Has output schema: true'), the description is complete enough. It covers the essential context without needing to explain return values or parameter details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with the parameter gundemMaddesiId fully documented in the schema. The description does not add any parameter-specific information beyond what the schema provides, so it meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('retrieving full text'), resource ('a KİK procurement decision'), and output format ('Markdown format'). It distinguishes from sibling tools like search_kik_v2_decisions by focusing on full document retrieval rather than search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states 'Use this when retrieving full text of a KİK procurement decision,' providing clear context for when to use this tool. It also references the sibling tool search_kik_v2_decisions in the parameter description, implying an alternative for initial searches.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/yargi-mcp'

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