import os, hmac, hashlib, time, json from typing import Optional, Dict, Any, List from fastapi import FastAPI, Header, HTTPException, Request from pydantic import BaseModel import uvicorn import numpy as np # app.py'nin en üstüne ekle (import'lardan sonra) try: from advanced_tools import advanced_tools ADVANCED_ENABLED = True print("[OK] Advanced tools loaded successfully!") except Exception as e: ADVANCED_ENABLED = False print(f"[WARN] Advanced tools not available: {e}") advanced_tools = None # Basit başlayalım - sadece temel tool'lar API_KEY = os.getenv("API_KEY", "") ALLOW_CLOCK_SKEW = 60 app = FastAPI(title="CPU-Only MCP Madness") # Güvenlik def verify_api_key(x_api_key: Optional[str]): if not API_KEY: raise HTTPException(status_code=500, detail="API_KEY not set") if not x_api_key or x_api_key != API_KEY: raise HTTPException(status_code=401, detail="Unauthorized") def verify_hmac(body: bytes, timestamp: Optional[str], signature: Optional[str]): if timestamp is None or signature is None: return try: ts = int(timestamp) except: raise HTTPException(status_code=400, detail="Invalid timestamp") now = int(time.time()) if abs(now - ts) > ALLOW_CLOCK_SKEW: raise HTTPException(status_code=401, detail="Stale request") secret = API_KEY.encode() base = f"{ts}\n".encode() + body expected = hmac.new(secret, base, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, signature): raise HTTPException(status_code=401, detail="Bad signature") # Request/Response modelleri class HandshakeResponse(BaseModel): ok: bool message: str tools: List[str] class MCPRequest(BaseModel): tool: str input: dict class MCPResponse(BaseModel): ok: bool result: dict # Basit tool'lar class SimpleTools: @staticmethod def echo(input_data: dict) -> dict: """Echo tool - ne gönderirsen geri alırsın""" return {"echoed": input_data, "timestamp": time.time()} @staticmethod def sum_numbers(input_data: dict) -> dict: """Sayıları toplar""" numbers = input_data.get("numbers", []) return { "sum": sum(numbers), "count": len(numbers), "average": sum(numbers) / len(numbers) if numbers else 0 } @staticmethod def text_stats(input_data: dict) -> dict: """Text istatistikleri""" text = input_data.get("text", "") return { "length": len(text), "words": len(text.split()), "sentences": text.count('.') + text.count('!') + text.count('?'), "uppercase": sum(1 for c in text if c.isupper()), "lowercase": sum(1 for c in text if c.islower()) } @staticmethod def personality_lite(input_data: dict) -> dict: """Basit personality dönüşümü""" text = input_data.get("text", "") style = input_data.get("style", "pirate") styles = { "pirate": { "prefix": "Arr matey! ", "suffix": " Shiver me timbers!", "replacements": { "hello": "ahoy", "friend": "matey", "yes": "aye", "you": "ye" } }, "robot": { "prefix": "[BEEP BOOP] ", "suffix": " [END TRANSMISSION]", "replacements": { "hello": "GREETINGS", "I": "THIS UNIT", "think": "COMPUTE", "feel": "PROCESS" } }, "yoda": { "prefix": "Hmm, ", "suffix": " it is.", "replacements": {} } } if style not in styles: style = "pirate" style_config = styles[style] result = text # Basit replacements for old, new in style_config["replacements"].items(): result = result.replace(old, new) # Prefix ve suffix ekle result = style_config["prefix"] + result + style_config["suffix"] return { "original": text, "styled": result, "style": style } @staticmethod def random_facts(input_data: dict) -> dict: """Random fun facts generator""" import random facts = [ "Octopuses have three hearts!", "Bananas are berries, but strawberries aren't!", "A day on Venus is longer than its year!", "Honey never spoils - archaeologists found 3000 year old honey that was still edible!", "The human brain uses 20% of the body's energy!", "There are more possible chess games than atoms in the universe!", "CPU stands for Central Processing Unit!", "The first computer bug was an actual bug - a moth!", "Python is named after Monty Python, not the snake!" ] topic = input_data.get("topic", "random").lower() if "animal" in topic: relevant_facts = [f for f in facts if any(a in f.lower() for a in ["octopus", "banana", "honey"])] elif "space" in topic: relevant_facts = [f for f in facts if "venus" in f.lower() or "universe" in f.lower()] elif "computer" in topic or "tech" in topic: relevant_facts = [f for f in facts if any(t in f.lower() for t in ["cpu", "computer", "python", "bug"])] else: relevant_facts = facts selected = random.sample(relevant_facts, min(3, len(relevant_facts))) return { "facts": selected, "topic": topic, "total_facts_available": len(relevant_facts) } # Tool registry # TOOLS dictionary'sini güncelle TOOLS = { "echo": SimpleTools.echo, "sum": SimpleTools.sum_numbers, "text_stats": SimpleTools.text_stats, "personality": SimpleTools.personality_lite, "facts": SimpleTools.random_facts, } # Advanced tools ekle (eğer yüklendiyse) if ADVANCED_ENABLED and advanced_tools: TOOLS.update({ "sentiment": advanced_tools.sentiment_analysis, "entities": advanced_tools.entity_extraction, "similarity": advanced_tools.semantic_similarity, "embedding": advanced_tools.text_embedding, "cache": advanced_tools.smart_cache, }) # Endpoints @app.get("/") async def root(): """Root endpoint - test için""" return { "message": "CPU-Only MCP Madness is running!", "status": "healthy", "available_tools": list(TOOLS.keys()), "advanced_enabled": ADVANCED_ENABLED, "total_tools": len(TOOLS) } @app.post("/handshake", response_model=HandshakeResponse) async def handshake( request: Request, x_api_key: Optional[str] = Header(default=None), x_timestamp: Optional[str] = Header(default=None), x_signature: Optional[str] = Header(default=None), ): body = await request.body() verify_api_key(x_api_key) verify_hmac(body, x_timestamp, x_signature) return HandshakeResponse( ok=True, message="Handshake successful! Ready to rock", tools=list(TOOLS.keys()) ) @app.post("/mcp/invoke", response_model=MCPResponse) async def mcp_invoke( payload: MCPRequest, request: Request, x_api_key: Optional[str] = Header(default=None), x_timestamp: Optional[str] = Header(default=None), x_signature: Optional[str] = Header(default=None), ): body = await request.body() verify_api_key(x_api_key) verify_hmac(body, x_timestamp, x_signature) tool_name = payload.tool tool_input = payload.input if tool_name not in TOOLS: raise HTTPException(status_code=404, detail=f"Unknown tool: {tool_name}") try: result = TOOLS[tool_name](tool_input) return MCPResponse(ok=True, result=result) except Exception as e: return MCPResponse(ok=False, result={"error": str(e)}) @app.get("/health") async def health(): """Health check""" return {"status": "healthy", "timestamp": time.time()} if __name__ == "__main__": port = int(os.getenv("PORT", "7860")) uvicorn.run("app:app", host="0.0.0.0", port=port, reload=False)