Use environment variables for OAuth URLs

Remove hard-coded URLs from OAuth configuration and use environment
variables instead for better security and configurability:

- Add CLERK_ISSUER and BASE_URL environment variables
- Update asgi_app.py OAuth endpoints to use env vars
- Update oauth_router.py to use configurable URLs
- Update .env.example with new environment variables
- Fix fetch tool bug: doc.content → doc.markdown_content

Environment variables:
- CLERK_ISSUER: Clerk domain issuer URL
- BASE_URL: Base URL for OAuth callbacks and API URLs
- CLERK_DOMAIN: Clerk domain name

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
saidsurucu
2025-07-01 22:37:44 +03:00
co-authored by Claude
parent 1aaf1e1bd4
commit c6daebe924
5 changed files with 613 additions and 26 deletions
+260
View File
@@ -2466,6 +2466,266 @@ def perform_cleanup():
atexit.register(perform_cleanup)
# --- ChatGPT Deep Research Compatible Tools ---
@app.tool(
description="ChatGPT Deep Research search for Turkish legal databases via Bedesten API - supports advanced search operators and multiple court types",
annotations={
"readOnlyHint": True,
"openWorldHint": True,
"idempotentHint": True
}
)
async def search(
query: str = Field(..., description="""Search query for Turkish legal documents via Bedesten API.
IMPORTANT: This tool is specifically designed for ChatGPT Deep Research.
Do NOT use for regular questions - use specific court tools instead.
Bedesten API Search Operators:
• Regular search: "mülkiyet kararı" - searches words separately (OR logic)
• Exact phrase: "\"mülkiyet kararı\"" - searches exact phrase (more precise)
• Required terms: "+mülkiyet +hak" - both terms must be present (AND logic)
• Excluded terms: "+mülkiyet -kira" - first term required, second excluded
• Combined: "+\"mülkiyet hakkı\" -\"kira sözleşmesi\"" - exact phrase required, exclude another
• Legal concepts: "\"idari işlem\"", "\"sözleşme ihlali\"", "\"tazminat davası\""
Searches across all Turkish courts via Bedesten unified API:
• Yargıtay (Court of Cassation) - Supreme court civil/criminal decisions
• Danıştay (Council of State) - Administrative court decisions
• Yerel Hukuk (Local Civil Courts) - First instance civil decisions
• İstinaf Hukuk (Civil Appeals Courts) - Appellate court decisions
• Kanun Yararına Bozma (KYB) - Extraordinary appeal decisions""")
) -> List[Dict[str, str]]:
"""
Bedesten API search tool for ChatGPT Deep Research compatibility.
This tool searches Turkish legal databases via the unified Bedesten API.
It supports advanced search operators and covers all major court types.
USAGE RESTRICTION: Only for ChatGPT Deep Research workflows.
For regular legal research, use specific court tools like search_yargitay_bedesten.
Returns:
Array of search result objects with id, title, text snippet, and url fields
as required by ChatGPT Deep Research specification.
"""
logger.info(f"ChatGPT Deep Research search tool called with query: {query}")
results = []
try:
# Search all court types via unified Bedesten API
court_types = [
("YARGITAYKARARI", "Yargıtay", "yargitay_bedesten"),
("DANISTAYKARAR", "Danıştay", "danistay_bedesten"),
("YERELHUKUK", "Yerel Hukuk Mahkemesi", "yerel_hukuk_bedesten"),
("ISTINAFHUKUK", "İstinaf Hukuk Mahkemesi", "istinaf_hukuk_bedesten"),
("KYB", "Kanun Yararına Bozma", "kyb_bedesten")
]
for item_type, court_name, id_prefix in court_types:
try:
search_results = await bedesten_client_instance.search_documents(
BedestenSearchRequest(
data=BedestenSearchData(
phrase=query, # Use query as-is to support both regular and exact phrase searches
itemTypeList=[item_type],
pageSize=10,
pageNumber=1
)
)
)
# Add results from this court type (limit to top 5 per court)
for decision in search_results.data.emsalKararList[:5]:
results.append({
"id": f"{id_prefix}_{decision.documentId}",
"title": f"{court_name} - {decision.birimAdi or 'Bilinmeyen Daire'} - {decision.esasNo or ''}/{decision.kararNo or ''}",
"text": f"{court_name} decision on '{query}' - Date: {decision.kararTarihi} - Court: {decision.birimAdi or 'Unknown'}",
"url": f"https://yargi-mcp.fly.dev/documents/{id_prefix}/{decision.documentId}"
})
logger.info(f"Found {len(search_results.data.emsalKararList)} results from {court_name}")
except Exception as e:
logger.warning(f"Bedesten API search error for {court_name}: {e}")
# Comment out other API implementations for ChatGPT Deep Research
"""
# Other API implementations disabled for ChatGPT Deep Research
# These are available through specific court tools:
# Yargıtay Official API - use search_yargitay_detailed instead
# Danıştay Official API - use search_danistay_by_keyword instead
# Constitutional Court - use search_anayasa_norm_denetimi_decisions instead
# Competition Authority - use search_rekabet_kurumu_decisions instead
# Public Procurement Authority - use search_kik_decisions instead
# Court of Accounts - use search_sayistay_* tools instead
# UYAP Emsal - use search_emsal_detailed_decisions instead
# Jurisdictional Disputes Court - use search_uyusmazlik_decisions instead
"""
logger.info(f"ChatGPT Deep Research search completed. Found {len(results)} results via Bedesten API.")
return results
except Exception as e:
logger.exception("Error in ChatGPT Deep Research search tool")
# Return partial results if any were found
if results:
return results
raise
@app.tool(
description="ChatGPT Deep Research fetch for Turkish legal documents via Bedesten API - retrieves complete document text in Markdown format",
annotations={
"readOnlyHint": True,
"openWorldHint": False, # Retrieves specific documents, not exploring
"idempotentHint": True
}
)
async def fetch(
id: str = Field(..., description="""Document identifier from search results via Bedesten API.
IMPORTANT: This tool is specifically designed for ChatGPT Deep Research.
Do NOT use for regular questions - use specific court document tools instead.
Supported ID formats from Bedesten API:
• yargitay_bedesten_{documentId} - Court of Cassation decisions
• danistay_bedesten_{documentId} - Council of State decisions
• yerel_hukuk_bedesten_{documentId} - Local Civil Court decisions
• istinaf_hukuk_bedesten_{documentId} - Civil Appeals Court decisions
• kyb_bedesten_{documentId} - Extraordinary Appeal decisions""")
) -> Dict[str, str]:
"""
Bedesten API fetch tool for ChatGPT Deep Research compatibility.
Retrieves the full text content of Turkish legal documents via unified Bedesten API.
Converts documents from HTML/PDF to clean Markdown format.
USAGE RESTRICTION: Only for ChatGPT Deep Research workflows.
For regular legal research, use specific court document tools.
Input Format:
• id: Document identifier from Bedesten API search results
(e.g., "yargitay_bedesten_ABC123", "danistay_bedesten_XYZ789")
Returns:
Single object with id, title, text (full Markdown content), url, and metadata fields
as required by ChatGPT Deep Research specification.
"""
logger.info(f"ChatGPT Deep Research fetch tool called for document ID: {id}")
if not id or not id.strip():
raise ValueError("Document ID must be a non-empty string")
try:
# Parse the document ID to determine court type and document identifier
if "_" not in id:
raise ValueError("Invalid document ID format. Expected: courttype_bedesten_documentid")
# Map of supported Bedesten API court types
court_mappings = {
"yargitay_bedesten_": {
"name": "Yargıtay (Court of Cassation)",
"level": "Supreme Court",
"jurisdiction": "Civil and Criminal Law"
},
"danistay_bedesten_": {
"name": "Danıştay (Council of State)",
"level": "Administrative Supreme Court",
"jurisdiction": "Administrative Law"
},
"yerel_hukuk_bedesten_": {
"name": "Yerel Hukuk Mahkemesi (Local Civil Court)",
"level": "First Instance Court",
"jurisdiction": "Civil Law"
},
"istinaf_hukuk_bedesten_": {
"name": "İstinaf Hukuk Mahkemesi (Civil Appeals Court)",
"level": "Appellate Court",
"jurisdiction": "Civil Law Appeals"
},
"kyb_bedesten_": {
"name": "Kanun Yararına Bozma (Extraordinary Appeal)",
"level": "Extraordinary Appeal",
"jurisdiction": "Extraordinary Legal Remedies"
}
}
# Find matching court type
court_info = None
doc_id = None
prefix = None
for court_prefix, info in court_mappings.items():
if id.startswith(court_prefix):
court_info = info
doc_id = id.replace(court_prefix, "")
prefix = court_prefix.rstrip("_")
break
if not court_info or not doc_id:
raise ValueError(f"Unsupported document ID format for ChatGPT Deep Research: {id}")
# Fetch document via Bedesten API
doc = await bedesten_client_instance.get_document_as_markdown(doc_id)
return {
"id": id,
"title": f"{court_info['name']} - Document {doc_id}",
"text": doc.markdown_content,
"url": f"https://yargi-mcp.fly.dev/documents/{prefix}/{doc_id}",
"metadata": {
"database": f"{court_info['name']} via Bedesten API",
"court_level": court_info['level'],
"jurisdiction": court_info['jurisdiction'],
"document_id": doc_id,
"api_source": "Bedesten Unified API",
"chatgpt_deep_research": True
}
}
# Comment out other API implementations for ChatGPT Deep Research
"""
# Other API implementations disabled for ChatGPT Deep Research
# These are available through specific court document tools:
elif id.startswith("yargitay_"):
# Yargıtay Official API - use get_yargitay_document_markdown instead
doc_id = id.replace("yargitay_", "")
doc = await yargitay_client_instance.get_decision_document_as_markdown(doc_id)
elif id.startswith("danistay_"):
# Danıştay Official API - use get_danistay_document_markdown instead
doc_id = id.replace("danistay_", "")
doc = await danistay_client_instance.get_decision_document_as_markdown(doc_id)
elif id.startswith("anayasa_"):
# Constitutional Court - use get_anayasa_norm_denetimi_document_markdown instead
doc_id = id.replace("anayasa_", "")
doc = await anayasa_norm_client_instance.get_decision_document_as_markdown(...)
elif id.startswith("rekabet_"):
# Competition Authority - use get_rekabet_kurumu_document instead
doc_id = id.replace("rekabet_", "")
doc = await rekabet_client_instance.get_decision_document(...)
elif id.startswith("kik_"):
# Public Procurement Authority - use get_kik_decision_document_as_markdown instead
doc_id = id.replace("kik_", "")
doc = await kik_client_instance.get_decision_document_as_markdown(doc_id)
elif id.startswith("local_"):
# This was already using Bedesten API, but deprecated for ChatGPT Deep Research
doc_id = id.replace("local_", "")
doc = await bedesten_client_instance.get_document_as_markdown(doc_id)
"""
except Exception as e:
logger.exception(f"Error fetching ChatGPT Deep Research document {id}")
raise
def main():
logger.info(f"Starting {app.name} server via main() function...")
logger.info(f"Logs will be written to: {LOG_FILE_PATH}")