Files
mdscrap/rag_local/mcp_server.py
Beyhan Oğur 9630a33ec1 first commit
2026-04-26 22:00:50 +03:00

89 lines
3.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import logging
import chromadb
from chromadb.utils import embedding_functions
from mcp.server.fastmcp import FastMCP
# Log ayarları: Sadece kendi loglarımızı yazalım, diğer kütüphaneler (httpx vb.) karışmasın.
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
logger = logging.getLogger("DocsRAGServer")
logger.setLevel(logging.INFO)
# Sadece bu logger için bir dosya işleyicisi (handler) ekleyelim
file_handler = logging.FileHandler(os.path.join(SCRIPT_DIR, 'mcp_server.log'))
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
logger.addHandler(file_handler)
# Propagate'i kapatalım ki root logger'a gitmesin
logger.propagate = False
# Dış kütüphanelerin gereksiz loglarını susturmak için:
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("sentence_transformers").setLevel(logging.WARNING)
logger.info("DocsRAGServer başlatılıyor...")
# MCP Server'ı oluştur
# FastMCP, standart stdio/SSE vb. ayarlarını otomatik halleder.
mcp = FastMCP("DocsRAGServer")
# Çalışma dizinine göre ChromaDB klasörünün yolunu bul
MAIN_DIR = os.path.dirname(SCRIPT_DIR)
CHROMA_PATH = os.path.join(MAIN_DIR, "chroma_db")
# ChromaDB'ye bağlan
# Not: Sunucu ayağa kalktığında sadece bir kez bağlanır.
try:
client = chromadb.PersistentClient(path=CHROMA_PATH)
sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="all-MiniLM-L6-v2")
collection = client.get_or_create_collection(name="docs", embedding_function=sentence_transformer_ef)
except Exception as e:
error_msg = f"UYARI: ChromaDB'ye bağlanırken hata oluştu. Henüz ingest.py çalıştırılmamış olabilir mi? Hata: {e}"
print(error_msg)
logger.error(error_msg)
@mcp.tool()
def search_documentation(query: str, num_results: int = 5) -> str:
"""
Kullanıcının sorusuna en uygun dokümantasyon parçalarını vektör veritabanından bulup döndürür.
Bu araç (tool) sistemin belleği gibi davranır ve AI'ın kod/kavram araması yapmasını sağlar.
Args:
query: Aranacak soru veya anahtar kelimeler (Örn: 'app router data fetching' veya 'next-auth credentials provider').
num_results: Döndürülecek maksimum sonuç sayısı (varsayılan: 5).
"""
logger.info(f"Arama isteği alındı: query='{query}', num_results={num_results}")
try:
# Sorguyu vektöre çevirip en benzer metinleri (semantic search) getir
results = collection.query(
query_texts=[query],
n_results=num_results
)
if not results['documents'] or not results['documents'][0]:
logger.info("Sorgu için ilgili bir doküman bulunamadı.")
return "İlgili bir doküman bulunamadı."
docs = results['documents'][0]
metadatas = results['metadatas'][0]
distances = results['distances'][0]
response_parts = [f"Arama Sorgusu: '{query}'\nBulunan En İyi Eşleşmeler:\n"]
for i, (doc, meta, dist) in enumerate(zip(docs, metadatas, distances)):
source = meta.get("source", "Bilinmeyen Kaynak")
# dist (distance) değeri ChromaDB için varsayılan olarak L2 mesafesidir, küçük olan daha benzerdir.
response_parts.append(f"--- Sonuç {i+1} (Kaynak: {source}, Uzaklık: {dist:.4f}) ---\n{doc}\n")
logger.info(f"Sorgu başarılı, {len(docs)} sonuç bulundu.")
return "\n".join(response_parts)
except Exception as e:
logger.error(f"Arama sırasında hata oluştu: {str(e)}")
return f"Arama sırasında hata oluştu: {str(e)}"
if __name__ == "__main__":
# Server'ı stdio üzerinden çalıştır. (Claude veya diğer MCP istemcileri bu şekilde bağlanır)
mcp.run()