import os import json import httpx from fastapi import FastAPI, HTTPException, APIRouter from datetime import datetime, timedelta from fastapi.middleware.cors import CORSMiddleware from fastmcp.server import FastMCP from contextlib import asynccontextmanager from typing import List, Dict, Optional # 初始化 MCP 服务器(必须在 FastAPI 之前) mcp_server = FastMCP(name="GitHubTrendingAPI") @asynccontextmanager async def lifespan(app: FastAPI): await fetch_github_trending() yield app = FastAPI(lifespan=lifespan) # CORS 配置 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 缓存变量 cached_trending = [] last_updated = None async def fetch_github_trending(): global cached_trending, last_updated headers = {"Accept": "application/vnd.github.v3+json"} if token := os.getenv("GITHUB_TOKEN"): headers["Authorization"] = f"token {token}" try: async with httpx.AsyncClient() as client: r = await client.get( "https://api.github.com/search/repositories", params={"q": "stars:>1000", "sort": "stars", "per_page": 10}, headers=headers ) r.raise_for_status() cached_trending = [ { "name": repo["full_name"], "url": repo["html_url"], "stars": repo["stargazers_count"] } for repo in r.json()["items"] ] last_updated = datetime.now() except Exception as e: print(f"Fetch error: {e}") if not cached_trending: raise HTTPException(500, "Failed to fetch data") @mcp_server.tool() async def get_trending_repos(num: int = 10) -> dict: if not last_updated or (datetime.now() - last_updated) > timedelta(minutes=30): await fetch_github_trending() return {"trending": cached_trending[:num]} # 关键修改:正确挂载MCP路由 # 方案1:直接挂载整个MCP应用 app.mount("/mcp", mcp_server.http_app()) # 方案2:或者使用APIRouter(如果方案1不行) # mcp_router = APIRouter() # mcp_router.include_router(mcp_server.http_app().router, prefix="") # app.include_router(mcp_router, prefix="/mcp") # 添加MCP健康检查路由 @app.get("/mcp/health") async def mcp_health_check(): return {"status": "ok", "mcp_version": "1.0"} @app.get("/") async def root(): # 添加更多有用的调试信息 return { "message": "API is running", "endpoints": { "mcp_tool": "/mcp/tool/get_trending_repos", "mcp_schema": "/mcp/schema", "mcp_health": "/mcp/health", "trending": "/trending" } } @app.get("/trending") async def get_trending(num: int = 10): if not cached_trending: await fetch_github_trending() return {"trending": cached_trending[:num]} # 在app.py中添加 @app.get("/mcp/") async def mcp_root(): return { "message": "MCP API root", "endpoints": { "tools": "/mcp/tool", "schema": "/mcp/schema" } }