mcp-cpu-madness / app.py
Cordobian's picture
Update app.py
feafc1e verified
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)