Skip to main content
Glama
app.py9.95 kB
# src/server/app.py """ Main application entry point. This module creates a hybrid application that supports both: - RESTful API (FastAPI) for standard HTTP JSON API calls - MCP Protocol (Streamable HTTP) for AI Agent integration Architecture: - /api/v1/* -> RESTful API endpoints - /mcp -> MCP protocol endpoint (JSON-RPC 2.0) - /health -> Health check endpoint - /docs -> OpenAPI documentation (Swagger UI) - /redoc -> ReDoc documentation """ from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from src.server.mcp.server import create_mcp_server from src.server.core.health import router as health_router from src.server.api.routes import market_data_router, filings_router from src.server.core.dependencies import Container from src.server.utils.logger import logger def create_app(): """Create the hybrid application: FastAPI + MCP Protocol Returns: FastAPI: Application instance with both RESTful API and MCP support """ # 1. Create MCP server instance early so we can integrate its lifespan mcp_server = None mcp_app = None try: mcp_server = create_mcp_server() mcp_app = mcp_server.streamable_http_app(path="/") except Exception as e: logger.error(f"Failed to create MCP server: {e}", exc_info=True) logger.warning("⚠️ MCP server creation failed, MCP features will be disabled") # 2. Define application lifespan - manages connections and adapters @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan - manages connections and adapters.""" # Startup logger.info("🚀 Starting application") # Initialize Redis redis = Container.redis() await redis.connect() logger.info("✅ Redis connection established") # Initialize Tushare connection tushare = Container.tushare() tushare_connected = await tushare.connect() if tushare_connected: logger.info("✅ Tushare connection established") else: logger.warning("⚠️ Tushare connection failed - will use fallback adapters") # Initialize FinnHub connection finnhub = Container.finnhub() await finnhub.connect() logger.info("✅ FinnHub connection established") # Initialize Baostock connection baostock = Container.baostock() await baostock.connect() logger.info("✅ Baostock connection established") # Register adapters logger.info("📦 Registering data adapters...") adapter_manager = Container.adapter_manager() # A股数据源 - 按优先级注册 adapter_manager.register_adapter(Container.tushare_adapter()) adapter_manager.register_adapter(Container.akshare_adapter()) adapter_manager.register_adapter(Container.baostock_adapter()) # 加密货币数据源 - 优先级高于 Yahoo(避免被覆盖) # 优先: CoinGecko (免费,数据准确,延迟低) adapter_manager.register_adapter(Container.crypto_adapter()) # 备选: CCXT (交易所直连,支持OHLCV) adapter_manager.register_adapter(Container.ccxt_adapter()) # 美股数据源(Yahoo 也支持加密货币,但优先级低) adapter_manager.register_adapter(Container.yahoo_adapter()) adapter_manager.register_adapter(Container.finnhub_adapter()) logger.info( "✅ All adapters registered (A-share priority: Tushare > Akshare > Baostock)" ) # Integrate MCP lifespan if available if mcp_app: logger.info("🔄 Initializing MCP server lifespan...") async with mcp_app.router.lifespan_context(mcp_app): yield else: yield # Shutdown logger.info("🛑 Shutting down application") # 3. Create FastAPI application app = FastAPI( title="Stock Tool Server", description=""" ## 🚀 金融数据服务器 提供两种协议支持,满足不同场景的集成需求: ### 📡 协议支持 #### 1. RESTful API (推荐用于 Java/Spring 集成) - **Base URL**: `/api/v1` - **文档**: [Swagger UI](/docs) | [ReDoc](/redoc) - **特点**: 标准 HTTP JSON API,易于集成 #### 2. MCP Protocol (用于 AI Agent 集成) - **Endpoint**: `/mcp` - **协议**: Streamable HTTP (JSON-RPC 2.0) - **用途**: Claude Desktop, Cursor 等 AI Agent ### 🎯 核心功能 - 📊 **批量价格查询**: 一次请求获取多个资产的实时价格 - 📈 **技术指标计算**: SMA, RSI, MACD, 布林带等 20+ 指标 - 🔍 **资产搜索**: 支持股票、加密货币、ETF 搜索 - 📰 **新闻与研究**: 获取市场新闻和深度研究报告 ### 🌍 支持的市场 - **美股**: NASDAQ, NYSE (通过 Yahoo Finance, Finnhub) - **A股**: 上交所, 深交所 (通过 Akshare, Tushare, Baostock) - **加密货币**: Binance, OKX 等 (通过 CCXT) ### 📖 快速开始 **RESTful API 示例:** ```bash # 批量获取价格 curl -X POST "http://localhost:9898/api/v1/market/prices/batch" \\ -H "Content-Type: application/json" \\ -d '{"tickers": ["BINANCE:BTCUSDT", "NASDAQ:AAPL"]}' # 计算技术指标 curl -X POST "http://localhost:9898/api/v1/market/indicators/calculate" \\ -H "Content-Type: application/json" \\ -d '{"symbol": "BINANCE:BTCUSDT", "period": "30d", "interval": "1d"}' ``` **MCP Protocol 示例:** ```bash curl -X POST "http://localhost:9898/mcp" \\ -H "Content-Type: application/json" \\ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_multiple_prices", "arguments": {"tickers": ["BINANCE:BTCUSDT"]} }, "id": "1" }' ``` """, version="1.0.0", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, # Use the inner lifespan function openapi_tags=[ { "name": "Market Data", "description": "市场数据 API - 价格查询和技术指标计算", }, {"name": "Health", "description": "健康检查 - 服务状态监控"}, {"name": "Root", "description": "根路径 - 服务信息"}, ], ) # 4. Add CORS middleware (允许跨域请求) app.add_middleware( CORSMiddleware, allow_origins=["*"], # 生产环境应限制具体域名 allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) logger.info("✅ CORS middleware configured") # 5. Register RESTful API routes app.include_router(health_router, tags=["Health"]) app.include_router(market_data_router, tags=["Market Data"]) app.include_router(filings_router, prefix="/api/v1", tags=["Filings"]) logger.info("✅ RESTful API routes registered") logger.info(" - Health check: /health") logger.info(" - Market data: /api/v1/market/*") logger.info(" - Filings: /api/v1/filings/*") # 6. Mount MCP protocol endpoint if mcp_app: try: app.mount("/mcp", mcp_app) logger.info("✅ MCP protocol endpoint mounted at /mcp") except Exception as e: logger.error(f"Failed to mount MCP endpoint: {e}", exc_info=True) logger.warning("⚠️ MCP endpoint not available, only RESTful API will work") # 7. Add root endpoint with service information @app.get("/", tags=["Root"]) async def root(): """Get service information and available endpoints""" return { "service": "Stock Tool Server", "version": "1.0.0", "description": "Financial data service with dual protocol support", "protocols": { "restful_api": { "description": "Standard HTTP JSON API", "base_url": "/api/v1", "documentation": { "swagger_ui": "/docs", "redoc": "/redoc", "openapi_json": "/openapi.json", }, "endpoints": { "batch_prices": "POST /api/v1/market/prices/batch", "technical_indicators": "POST /api/v1/market/indicators/calculate", }, }, "mcp": { "description": "Model Context Protocol (for AI Agents)", "endpoint": "/mcp", "protocol": "Streamable HTTP (JSON-RPC 2.0)", "tools_count": 20, }, }, "health_check": "/health", "supported_markets": ["US Stocks", "China A-Shares", "Cryptocurrency"], "supported_exchanges": ["NASDAQ", "NYSE", "SSE", "SZSE", "BINANCE", "OKX"], } logger.info("=" * 70) logger.info("🚀 Stock Tool Server Initialized") logger.info("=" * 70) logger.info("📡 Protocols:") logger.info(" - RESTful API: http://localhost:9898/api/v1") logger.info(" - MCP Protocol: http://localhost:9898/mcp") logger.info("📖 Documentation:") logger.info(" - Swagger UI: http://localhost:9898/docs") logger.info(" - ReDoc: http://localhost:9898/redoc") logger.info("💚 Health Check: http://localhost:9898/health") logger.info("=" * 70) return app # Create the app instance app = create_app()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/huweihua123/stock-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server