Skip to main content
Glama

search_tenders

Search Turkish government tenders from EKAP v2 portal using text, date ranges, tender types, provinces, and detailed criteria to find relevant procurement opportunities.

Instructions

Search Turkish government tenders from EKAP v2 portal.

Tender types: 1=Mal, 2=Yapım, 3=Hizmet, 4=Danışmanlık Provinces: Use plate numbers (6=Ankara, 34=İstanbul, 35=İzmir) IKN format: YEAR/NUMBER, dates: YYYY-MM-DD

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
alt_yuklenici_calistirilabilir_miNoFilter for subcontractor employment allowed
alternatif_teklif_verilebilir_miNoFilter for alternative proposals allowed
announcement_date_endNoEnd date for announcement dates (YYYY-MM-DD format)
announcement_date_filterNoAnnouncement date filter type
announcement_date_startNoStart date for announcement dates (YYYY-MM-DD format)
announcement_typesNoAnnouncement type IDs: 1=Ön İlan, 2=İhale İlanı, 3=Sonuç İlanı, etc.
authority_idsNoAuthority/institution IDs to filter by
avans_verilecek_miNoFilter for advance payment to be given
cerceve_anlasmasi_miNoFilter for framework agreements
e_eksiltme_yapilacak_miNoFilter for electronic auctions (Elektronik eksiltme yapılacak mı)
e_ihaleNoFilter for electronic tenders (e-İhale)
ekonomik_mali_yeterlilik_belgeleri_isteniyor_muNoFilter for economic/financial qualification documents required
fiyat_disi_unsur_varmiNoFilter for non-price factors (Fiyat dışı unsur var mı)
fiyat_farki_verilecek_miNoFilter for price difference to be given
ikn_numberNoIKN number
ikn_yearNoIKN year (e.g., 2025)
is_deneyimi_gosteren_belgeler_isteniyor_muNoFilter for work experience documents required
kismi_teklif_miNoFilter for partial proposals (Kısmi teklif verilebilir mi)
konsorsiyum_katilabilir_miNoFilter for consortium participation allowed
limitNoMaximum number of results to return (1-100)
mesleki_teknik_yeterlilik_belgeleri_isteniyor_muNoFilter for professional/technical qualification documents required
okas_codesNoOKAS classification codes to filter by
order_byNoOrder results by: ihaleTarihi=date, ihaleAdi=name, idareAdi=authorityihaleTarihi
ortak_alim_miNoFilter for joint procurement (Ortak alım mı)
personel_calistirilmasina_dayali_miNoFilter for personnel employment based tenders
proposal_typesNoProposal type IDs: 1=Götürü-Anahtar Teslimi Götürü, 2=Birim Fiyat, 3=Karma
provincesNoProvince plate numbers to filter by (1-81, e.g., 6=Ankara, 34=İstanbul, 35=İzmir). Accepts integers or strings.
search_in_admin_specNoSearch in administrative specifications
search_in_announcementNoSearch in tender announcement
search_in_bid_formNoSearch in bid form
search_in_contract_draftNoSearch in contract draft
search_in_iknNoSearch in IKN (tender reference number)
search_in_locationNoSearch in work location clause
search_in_nature_quantityNoSearch in nature/quantity clause
search_in_similar_workNoSearch in similar work clause
search_in_tech_specNoSearch in technical specifications
search_in_tender_infoNoSearch in tender information
search_in_titleNoSearch in tender title
search_textNoText to search for in tender titles, descriptions, and specifications
search_typeNoSearch type: GirdigimGibi=exact match, TumKelimeler=all wordsGirdigimGibi
skipNoNumber of results to skip for pagination
sort_orderNoSort orderdesc
tender_date_endNoEnd date for tender dates (YYYY-MM-DD format)
tender_date_filterNoTender date filter type
tender_date_startNoStart date for tender dates (YYYY-MM-DD format)
tender_methodsNoTender method IDs to filter by
tender_statusesNoTender status IDs to filter by
tender_sub_methodsNoTender sub-method IDs to filter by
tender_typesNoTender types: 1=Mal (Goods), 2=Yapım (Construction), 3=Hizmet (Service), 4=Danışmanlık (Consultancy)
yabanci_isteklilere_izin_veriliyor_muNoFilter for foreign bidders allowed
yerli_istekliye_fiyat_avantaji_uygulanıyor_muNoFilter for domestic bidder price advantage applied

Implementation Reference

  • ihale_mcp.py:37-37 (registration)
    The @mcp.tool decorator registers the search_tenders function as an MCP tool.
    @mcp.tool
  • Input schema and type definitions for the search_tenders tool using Pydantic Annotated fields with descriptions, defaults, enums, and validation.
    async def search_tenders( search_text: Annotated[str, "Text to search for in tender titles, descriptions, and specifications"] = "", ikn_year: Annotated[Optional[int], "IKN year (e.g., 2025)"] = None, ikn_number: Annotated[Optional[int], "IKN number"] = None, tender_types: Annotated[List[Literal[1, 2, 3, 4]], "Tender types: 1=Mal (Goods), 2=Yapım (Construction), 3=Hizmet (Service), 4=Danışmanlık (Consultancy)"] = None, tender_date_start: Annotated[Optional[str], "Start date for tender dates (YYYY-MM-DD format)"] = None, tender_date_end: Annotated[Optional[str], "End date for tender dates (YYYY-MM-DD format)"] = None, announcement_date_start: Annotated[Optional[str], "Start date for announcement dates (YYYY-MM-DD format)"] = None, announcement_date_end: Annotated[Optional[str], "End date for announcement dates (YYYY-MM-DD format)"] = None, announcement_date_filter: Annotated[Literal["today", "date_range"], "Announcement date filter type"] = None, tender_date_filter: Annotated[Literal["from_today", "date_range"], "Tender date filter type"] = None, search_type: Annotated[Literal["GirdigimGibi", "TumKelimeler"], "Search type: GirdigimGibi=exact match, TumKelimeler=all words"] = "GirdigimGibi", order_by: Annotated[Literal["ihaleTarihi", "ihaleAdi", "idareAdi"], "Order results by: ihaleTarihi=date, ihaleAdi=name, idareAdi=authority"] = "ihaleTarihi", sort_order: Annotated[Literal["asc", "desc"], "Sort order"] = "desc", # Boolean filters e_ihale: Annotated[Optional[bool], "Filter for electronic tenders (e-İhale)"] = None, e_eksiltme_yapilacak_mi: Annotated[Optional[bool], "Filter for electronic auctions (Elektronik eksiltme yapılacak mı)"] = None, ortak_alim_mi: Annotated[Optional[bool], "Filter for joint procurement (Ortak alım mı)"] = None, kismi_teklif_mi: Annotated[Optional[bool], "Filter for partial proposals (Kısmi teklif verilebilir mi)"] = None, fiyat_disi_unsur_varmi: Annotated[Optional[bool], "Filter for non-price factors (Fiyat dışı unsur var mı)"] = None, ekonomik_mali_yeterlilik_belgeleri_isteniyor_mu: Annotated[Optional[bool], "Filter for economic/financial qualification documents required"] = None, mesleki_teknik_yeterlilik_belgeleri_isteniyor_mu: Annotated[Optional[bool], "Filter for professional/technical qualification documents required"] = None, is_deneyimi_gosteren_belgeler_isteniyor_mu: Annotated[Optional[bool], "Filter for work experience documents required"] = None, yerli_istekliye_fiyat_avantaji_uygulanıyor_mu: Annotated[Optional[bool], "Filter for domestic bidder price advantage applied"] = None, yabanci_isteklilere_izin_veriliyor_mu: Annotated[Optional[bool], "Filter for foreign bidders allowed"] = None, alternatif_teklif_verilebilir_mi: Annotated[Optional[bool], "Filter for alternative proposals allowed"] = None, konsorsiyum_katilabilir_mi: Annotated[Optional[bool], "Filter for consortium participation allowed"] = None, alt_yuklenici_calistirilabilir_mi: Annotated[Optional[bool], "Filter for subcontractor employment allowed"] = None, fiyat_farki_verilecek_mi: Annotated[Optional[bool], "Filter for price difference to be given"] = None, avans_verilecek_mi: Annotated[Optional[bool], "Filter for advance payment to be given"] = None, cerceve_anlasmasi_mi: Annotated[Optional[bool], "Filter for framework agreements"] = None, personel_calistirilmasina_dayali_mi: Annotated[Optional[bool], "Filter for personnel employment based tenders"] = None, # List filters provinces: Annotated[List[int], "Province plate numbers to filter by (1-81, e.g., 6=Ankara, 34=İstanbul, 35=İzmir)"] = None, tender_statuses: Annotated[List[int], "Tender status IDs to filter by"] = None, tender_methods: Annotated[List[int], "Tender method IDs to filter by"] = None, tender_sub_methods: Annotated[List[int], "Tender sub-method IDs to filter by"] = None, okas_codes: Annotated[List[str], "OKAS classification codes to filter by"] = None, authority_ids: Annotated[List[int], "Authority/institution IDs to filter by"] = None, proposal_types: Annotated[List[int], "Proposal type IDs: 1=Götürü-Anahtar Teslimi Götürü, 2=Birim Fiyat, 3=Karma"] = None, announcement_types: Annotated[List[int], "Announcement type IDs: 1=Ön İlan, 2=İhale İlanı, 3=Sonuç İlanı, etc."] = None, # Search scope parameters search_in_ikn: Annotated[bool, "Search in IKN (tender reference number)"] = True, search_in_title: Annotated[bool, "Search in tender title"] = True, search_in_announcement: Annotated[bool, "Search in tender announcement"] = True, search_in_tech_spec: Annotated[bool, "Search in technical specifications"] = True, search_in_admin_spec: Annotated[bool, "Search in administrative specifications"] = True, search_in_similar_work: Annotated[bool, "Search in similar work clause"] = True, search_in_location: Annotated[bool, "Search in work location clause"] = True, search_in_nature_quantity: Annotated[bool, "Search in nature/quantity clause"] = True, search_in_tender_info: Annotated[bool, "Search in tender information"] = True, search_in_contract_draft: Annotated[bool, "Search in contract draft"] = True, search_in_bid_form: Annotated[bool, "Search in bid form"] = True, limit: Annotated[int, "Maximum number of results to return (1-100)"] = 10, skip: Annotated[int, "Number of results to skip for pagination"] = 0 ) -> Dict[str, Any]:
  • Handler logic: validates limits, handles special date filters like 'today', converts province plates to API IDs, calls EKAPClient, augments result with search params.
    # Validate limit if limit > 100: limit = 100 elif limit < 1: limit = 1 # Handle special date filters if announcement_date_filter == "today": today = datetime.now().strftime("%Y-%m-%d") announcement_date_start = today announcement_date_end = today if tender_date_filter == "from_today": today = datetime.now().strftime("%Y-%m-%d") tender_date_start = today tender_date_end = None # Convert plate numbers to API IDs api_province_ids = None if provinces: api_province_ids = [] for plate_number in provinces: api_id = PLATE_TO_API_ID.get(plate_number) if api_id: api_province_ids.append(api_id) # If no valid plate numbers, set to None to avoid empty filter if not api_province_ids: api_province_ids = None # Use the client to search tenders result = await ekap_client.search_tenders( search_text=search_text, ikn_year=ikn_year, ikn_number=ikn_number, tender_types=tender_types, tender_date_start=tender_date_start, tender_date_end=tender_date_end, announcement_date_start=announcement_date_start, announcement_date_end=announcement_date_end, search_type=search_type, order_by=order_by, sort_order=sort_order, # Boolean filters e_ihale=e_ihale, e_eksiltme_yapilacak_mi=e_eksiltme_yapilacak_mi, ortak_alim_mi=ortak_alim_mi, kismi_teklif_mi=kismi_teklif_mi, fiyat_disi_unsur_varmi=fiyat_disi_unsur_varmi, ekonomik_mali_yeterlilik_belgeleri_isteniyor_mu=ekonomik_mali_yeterlilik_belgeleri_isteniyor_mu, mesleki_teknik_yeterlilik_belgeleri_isteniyor_mu=mesleki_teknik_yeterlilik_belgeleri_isteniyor_mu, is_deneyimi_gosteren_belgeler_isteniyor_mu=is_deneyimi_gosteren_belgeler_isteniyor_mu, yerli_istekliye_fiyat_avantaji_uygulanıyor_mu=yerli_istekliye_fiyat_avantaji_uygulanıyor_mu, yabanci_isteklilere_izin_veriliyor_mu=yabanci_isteklilere_izin_veriliyor_mu, alternatif_teklif_verilebilir_mi=alternatif_teklif_verilebilir_mi, konsorsiyum_katilabilir_mi=konsorsiyum_katilabilir_mi, alt_yuklenici_calistirilabilir_mi=alt_yuklenici_calistirilabilir_mi, fiyat_farki_verilecek_mi=fiyat_farki_verilecek_mi, avans_verilecek_mi=avans_verilecek_mi, cerceve_anlasmasi_mi=cerceve_anlasmasi_mi, personel_calistirilmasina_dayali_mi=personel_calistirilmasina_dayali_mi, # List filters (provinces converted to API IDs) provinces=api_province_ids, tender_statuses=tender_statuses, tender_methods=tender_methods, tender_sub_methods=tender_sub_methods, okas_codes=okas_codes, authority_ids=authority_ids, proposal_types=proposal_types, announcement_types=announcement_types, # Search scope search_in_ikn=search_in_ikn, search_in_title=search_in_title, search_in_announcement=search_in_announcement, search_in_tech_spec=search_in_tech_spec, search_in_admin_spec=search_in_admin_spec, search_in_similar_work=search_in_similar_work, search_in_location=search_in_location, search_in_nature_quantity=search_in_nature_quantity, search_in_tender_info=search_in_tender_info, search_in_contract_draft=search_in_contract_draft, search_in_bid_form=search_in_bid_form, skip=skip, limit=limit ) # Add search parameters to result for logging if "search_params" not in result: result["search_params"] = { "search_text": search_text, "ikn_year": ikn_year, "ikn_number": ikn_number, "tender_types": tender_types, "date_range": { "tender_start": tender_date_start, "tender_end": tender_date_end, "announcement_start": announcement_date_start, "announcement_end": announcement_date_end } } return result
  • Core helper method in EKAPClient class that constructs the detailed API payload for EKAP v2 tender search endpoint, performs the HTTP request, processes and formats the raw API response into structured tender objects, including optional document URL fetching.
    async def search_tenders( self, search_text: str = "", ikn_year: Optional[int] = None, ikn_number: Optional[int] = None, tender_types: List[int] = None, tender_date_start: Optional[str] = None, tender_date_end: Optional[str] = None, announcement_date_start: Optional[str] = None, announcement_date_end: Optional[str] = None, search_type: Literal["GirdigimGibi", "TumKelimeler"] = "GirdigimGibi", order_by: Literal["ihaleTarihi", "ihaleAdi", "idareAdi"] = "ihaleTarihi", sort_order: Literal["asc", "desc"] = "desc", # Boolean filters e_ihale: Optional[bool] = None, e_eksiltme_yapilacak_mi: Optional[bool] = None, ortak_alim_mi: Optional[bool] = None, kismi_teklif_mi: Optional[bool] = None, fiyat_disi_unsur_varmi: Optional[bool] = None, ekonomik_mali_yeterlilik_belgeleri_isteniyor_mu: Optional[bool] = None, mesleki_teknik_yeterlilik_belgeleri_isteniyor_mu: Optional[bool] = None, is_deneyimi_gosteren_belgeler_isteniyor_mu: Optional[bool] = None, yerli_istekliye_fiyat_avantaji_uygulanıyor_mu: Optional[bool] = None, yabanci_isteklilere_izin_veriliyor_mu: Optional[bool] = None, alternatif_teklif_verilebilir_mi: Optional[bool] = None, konsorsiyum_katilabilir_mi: Optional[bool] = None, alt_yuklenici_calistirilabilir_mi: Optional[bool] = None, fiyat_farki_verilecek_mi: Optional[bool] = None, avans_verilecek_mi: Optional[bool] = None, cerceve_anlasmasi_mi: Optional[bool] = None, personel_calistirilmasina_dayali_mi: Optional[bool] = None, # List filters provinces: List[int] = None, tender_statuses: List[int] = None, tender_methods: List[int] = None, tender_sub_methods: List[int] = None, okas_codes: List[str] = None, authority_ids: List[int] = None, proposal_types: List[int] = None, announcement_types: List[int] = None, # Search scope parameters search_in_ikn: bool = True, search_in_title: bool = True, search_in_announcement: bool = True, search_in_tech_spec: bool = True, search_in_admin_spec: bool = True, search_in_similar_work: bool = True, search_in_location: bool = True, search_in_nature_quantity: bool = True, search_in_tender_info: bool = True, search_in_contract_draft: bool = True, search_in_bid_form: bool = True, skip: int = 0, limit: int = 10 ) -> Dict[str, Any]: """Search for Turkish government tenders""" # Province filtering is now handled by the API directly # Build API request payload api_params = { "searchText": search_text, "filterType": None, "ikNdeAra": search_in_ikn, "ihaleAdindaAra": search_in_title, "ihaleIlanindaAra": search_in_announcement, "teknikSartnamedeAra": search_in_tech_spec, "idariSartnamedeAra": search_in_admin_spec, "benzerIsMaddesindeAra": search_in_similar_work, "isinYapilacagiYerMaddesindeAra": search_in_location, "nitelikTurMiktarMaddesindeAra": search_in_nature_quantity, "ihaleBilgilerindeAra": search_in_tender_info, "sozlesmeTasarisindaAra": search_in_contract_draft, "teklifCetvelindeAra": search_in_bid_form, "searchType": search_type, "iknYili": ikn_year, "iknSayi": ikn_number, "ihaleTarihSaatBaslangic": self._format_date_for_api(tender_date_start), "ihaleTarihSaatBitis": self._format_date_for_api(tender_date_end), "ilanTarihSaatBaslangic": self._format_date_for_api(announcement_date_start), "ilanTarihSaatBitis": self._format_date_for_api(announcement_date_end), "yasaKapsami4734List": [], "ihaleTuruIdList": tender_types or [], "ihaleUsulIdList": tender_methods or [], "ihaleUsulAltIdList": tender_sub_methods or [], "ihaleIlIdList": provinces or [], "ihaleDurumIdList": tender_statuses or [], "idareIdList": authority_ids or [], "ihaleIlanTuruIdList": announcement_types or [], "teklifTuruIdList": proposal_types or [], "asiriDusukTeklifIdList": [], "istisnaMaddeIdList": [], "okasBransKodList": okas_codes or [], "okasBransAdiList": [], "titubbKodList": [], "gmdnKodList": [], # Boolean filters "eIhale": e_ihale, "eEksiltmeYapilacakMi": e_eksiltme_yapilacak_mi, "ortakAlimMi": ortak_alim_mi, "kismiTeklifMi": kismi_teklif_mi, "fiyatDisiUnsurVarmi": fiyat_disi_unsur_varmi, "ekonomikVeMaliYeterlilikBelgeleriIsteniyorMu": ekonomik_mali_yeterlilik_belgeleri_isteniyor_mu, "meslekiTeknikYeterlilikBelgeleriIsteniyorMu": mesleki_teknik_yeterlilik_belgeleri_isteniyor_mu, "isDeneyimiGosterenBelgelerIsteniyorMu": is_deneyimi_gosteren_belgeler_isteniyor_mu, "yerliIstekliyeFiyatAvantajiUgulaniyorMu": yerli_istekliye_fiyat_avantaji_uygulanıyor_mu, "yabanciIsteklilereIzinVeriliyorMu": yabanci_isteklilere_izin_veriliyor_mu, "alternatifTeklifVerilebilirMi": alternatif_teklif_verilebilir_mi, "konsorsiyumKatilabilirMi": konsorsiyum_katilabilir_mi, "altYukleniciCalistirilabilirMi": alt_yuklenici_calistirilabilir_mi, "fiyatFarkiVerilecekMi": fiyat_farki_verilecek_mi, "avansVerilecekMi": avans_verilecek_mi, "cerceveAnlasmaMi": cerceve_anlasmasi_mi, "personelCalistirilmasinaDayaliMi": personel_calistirilmasina_dayali_mi, "orderBy": order_by, "siralamaTipi": sort_order, "paginationSkip": skip, "paginationTake": limit } try: # Make API request response_data = await self._make_request(self.tender_endpoint, api_params) # Parse and format the response tenders = response_data.get("list", []) total_count = response_data.get("totalCount", 0) # Province filtering is now handled by the API directly # Format each tender for better readability formatted_tenders = [] for tender in tenders: tender_id = tender.get("id") # Get document URL for this tender document_url = None if tender_id and tender.get("dokumanSayisi", 0) > 0: try: doc_result = await self.get_tender_document_url(tender_id) if doc_result.get("success"): document_url = doc_result.get("document_url") except Exception: # If document URL fails, continue without it pass formatted_tender = { "id": tender_id, "name": tender.get("ihaleAdi"), "ikn": tender.get("ikn"), "type": { "code": tender.get("ihaleTip"), "description": tender.get("ihaleTipAciklama") }, "method": tender.get("ihaleUsulAciklama"), "status": { "code": tender.get("ihaleDurum"), "description": tender.get("ihaleDurumAciklama") }, "authority": tender.get("idareAdi"), "province": tender.get("ihaleIlAdi"), "tender_datetime": tender.get("ihaleTarihSaat"), "document_count": tender.get("dokumanSayisi", 0), "has_announcement": tender.get("ilanVarMi", False), "document_url": document_url } formatted_tenders.append(formatted_tender) result = { "tenders": formatted_tenders, "total_count": total_count, "returned_count": len(formatted_tenders) } # Province filtering is now handled by the API directly return result except httpx.HTTPStatusError as e: return { "error": f"API request failed with status {e.response.status_code}", "message": str(e) } except Exception as e: return { "error": "Request failed", "message": str(e) }

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

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