Files
auto-stock/mcp-server/main.py
2025-11-14 11:05:31 +09:00

187 lines
5.3 KiB
Python

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Dict, Any, List
import logging
from config import settings
from claude_client import claude_client
from perplexity_client import perplexity_client
from mcp_tools import mcp_tools
# AI 클라이언트 선택
ai_client = perplexity_client if settings.AI_PROVIDER == "perplexity" else claude_client
# 로깅 설정
logging.basicConfig(
level=getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
app = FastAPI(
title="Auto Stock Trading MCP Server",
description="Model Context Protocol Server for Stock Trading with Claude AI",
version="1.0.0"
)
# CORS 설정
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class ToolCallRequest(BaseModel):
tool_name: str
parameters: Dict[str, Any]
class AnalysisRequest(BaseModel):
analysis_type: str # RULE_VALIDATION, MARKET_ANALYSIS, RISK_ASSESSMENT
data: Dict[str, Any]
@app.get("/")
async def root():
return {
"message": "MCP Server for Auto Stock Trading",
"version": "1.0.0",
"status": "running"
}
@app.get("/health")
async def health_check():
return {
"status": "healthy",
"ai_provider": settings.AI_PROVIDER,
"claude_configured": bool(settings.ANTHROPIC_API_KEY),
"perplexity_configured": bool(settings.PERPLEXITY_API_KEY)
}
@app.get("/tools")
async def list_tools():
"""사용 가능한 도구 목록"""
return {
"tools": mcp_tools.get_tool_definitions()
}
@app.post("/tools/call")
async def call_tool(request: ToolCallRequest):
"""MCP 도구 호출"""
try:
result = await mcp_tools.call_tool(request.tool_name, request.parameters)
return result
except Exception as e:
logger.error(f"Tool call error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/analyze")
async def analyze(request: AnalysisRequest):
"""Claude를 통한 분석"""
try:
analysis_type = request.analysis_type
data = request.data
if analysis_type == "RULE_VALIDATION":
# 규칙 검증
rule = data.get("rule")
market_data = data.get("market_data")
if not rule or not market_data:
raise HTTPException(
status_code=400,
detail="rule and market_data are required"
)
result = await ai_client.validate_trading_rule(rule, market_data)
return {
"analysis_type": analysis_type,
"result": result
}
elif analysis_type == "MARKET_ANALYSIS":
# 시장 분석
stock_code = data.get("stock_code")
market_data = data.get("market_data")
news = data.get("news", [])
if not stock_code or not market_data:
raise HTTPException(
status_code=400,
detail="stock_code and market_data are required"
)
result = await ai_client.analyze_market(stock_code, market_data, news)
return {
"analysis_type": analysis_type,
"result": result
}
elif analysis_type == "RISK_ASSESSMENT":
# 리스크 평가
portfolio = data.get("portfolio")
trade_plan = data.get("trade_plan")
if not portfolio or not trade_plan:
raise HTTPException(
status_code=400,
detail="portfolio and trade_plan are required"
)
result = await ai_client.assess_risk(portfolio, trade_plan)
return {
"analysis_type": analysis_type,
"result": result
}
elif analysis_type == "FAIR_PRICE":
# 적정가 분석
stock_code = data.get("stock_code")
market_data = data.get("market_data")
financial_data = data.get("financial_data")
if not stock_code or not market_data:
raise HTTPException(
status_code=400,
detail="stock_code and market_data are required"
)
result = await ai_client.calculate_fair_price(
stock_code, market_data, financial_data
)
return {
"analysis_type": analysis_type,
"result": result
}
else:
raise HTTPException(
status_code=400,
detail=f"Unknown analysis type: {analysis_type}"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Analysis error: {e}")
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host=settings.MCP_SERVER_HOST,
port=settings.MCP_SERVER_PORT,
reload=True
)