feat: change the file directory and support authentication

This commit is contained in:
Chenyme committed 2025-10-17 10:56:06 +08:00
1 parent c178b988c3
commit df32f6f1c6
6 files changed
+78 -21

No files matched your search

+30
View File
@@ -7,6 +7,27 @@ from logging.handlers import RotatingFileHandler
from app.core.config import setting
class MCPLogFilter(logging.Filter):
"""MCP 日志过滤器 - 过滤掉包含大量数据的 DEBUG 日志"""
def filter(self, record):
# 过滤掉包含原始字节数据的 SSE 日志
if record.name == "sse_starlette.sse" and "chunk: b'" in record.getMessage():
return False
# 过滤掉 SSE 的一些冗余日志
if record.name == "sse_starlette.sse" and record.levelno == logging.DEBUG:
msg = record.getMessage()
if any(x in msg for x in ["Got event:", "Closing", "chunk:"]):
return False
# 过滤掉 MCP streamable_http 的一些 DEBUG 日志
if "mcp.server.streamable_http" in record.name and record.levelno == logging.DEBUG:
return False
return True
class LoggerManager:
"""日志管理器"""
@@ -35,10 +56,14 @@ class LoggerManager:
# 创建格式器
formatter = logging.Formatter(log_format)
# 创建日志过滤器
mcp_filter = MCPLogFilter()
# 控制台处理器
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(log_level)
console_handler.setFormatter(formatter)
console_handler.addFilter(mcp_filter)
# 文件处理器
file_handler = RotatingFileHandler(
@@ -46,6 +71,7 @@ class LoggerManager:
)
file_handler.setLevel(log_level)
file_handler.setFormatter(formatter)
file_handler.addFilter(mcp_filter)
# 添加处理器到根日志器
self.logger.addHandler(console_handler)
@@ -57,6 +83,10 @@ class LoggerManager:
logging.getLogger("fastapi").setLevel(logging.INFO)
logging.getLogger("aiomysql").setLevel(logging.WARNING)
# FastMCP 相关日志 - 关闭
logging.getLogger("mcp").setLevel(logging.CRITICAL)
logging.getLogger("fastmcp").setLevel(logging.CRITICAL)
LoggerManager._initialized = True
def debug(self, msg: str) -> None:
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""MCP模块初始化"""
from app.mcp.server import mcp
from app.services.mcp.server import mcp
__all__ = ["mcp"]
@@ -2,13 +2,39 @@
"""FastMCP服务器实例"""
from fastmcp import FastMCP
from app.mcp.tools import ask_grok_impl
from fastmcp.server.auth.providers.jwt import StaticTokenVerifier
from app.services.mcp.tools import ask_grok_impl
from app.core.config import setting
# 创建FastMCP实例 - 不在这里设置stateless_http
mcp = FastMCP(
name="Grok2API-MCP",
instructions="MCP server providing Grok AI chat capabilities. Use ask_grok tool to interact with Grok AI models."
)
def create_mcp_server() -> FastMCP:
"""创建MCP服务器实例,如果配置了API密钥则启用认证"""
# 检查是否配置了API密钥
api_key = setting.grok_config.get("api_key")
# 如果配置了API密钥,则启用静态token验证
auth = None
if api_key:
auth = StaticTokenVerifier(
tokens={
api_key: {
"client_id": "grok2api-client",
"scopes": ["read", "write", "admin"]
}
},
required_scopes=["read"]
)
# 创建FastMCP实例
return FastMCP(
name="Grok2API-MCP",
instructions="MCP server providing Grok AI chat capabilities. Use ask_grok tool to interact with Grok AI models.",
auth=auth
)
# 创建全局MCP实例
mcp = create_mcp_server()
# 注册ask_grok工具
@@ -38,7 +38,7 @@ async def ask_grok_impl(
"stream": True
}
logger.info(f"[MCP] ask_grok调用 - 模型:{model}, 问题长度:{len(query)}")
logger.info(f"[MCP] ask_grok 调用, 模型: {model}")
# 调用Grok客户端(流式)
response_iterator = await GrokClient.openai_to_grok(request_data)
@@ -66,7 +66,7 @@ async def ask_grok_impl(
continue
result = "".join(content_parts)
logger.info(f"[MCP] ask_grok完成 - 响应长度:{len(result)}")
logger.info(f"[MCP] ask_grok 完成, 响应长度: {len(result)}")
return result
except GrokApiException as e:
+12 -11
View File
@@ -13,11 +13,12 @@ from app.api.v1.models import router as models_router
from app.api.v1.images import router as images_router
from app.api.admin.manage import router as admin_router
# 导入MCP服务器
from app.mcp import mcp
# 导入MCP服务器(认证配置在server.py中完成)
from app.services.mcp import mcp
# 创建MCP的FastAPI应用实例
mcp_app = mcp.http_app(stateless_http=True)
# 使用流式HTTP传输,支持高效的双向流式通信
mcp_app = mcp.http_app(stateless_http=True, transport="streamable-http")
# 2. 定义应用生命周期
@asynccontextmanager
@@ -40,7 +41,7 @@ async def lifespan(app: FastAPI):
setting.set_storage(storage)
token_manager.set_storage(storage)
# 重新加载配置和token数据(从存储同步)
# 重新加载配置和token数据
await setting.reload()
token_manager._load_data()
logger.info("[Grok2API] 核心服务初始化完成")
@@ -48,9 +49,9 @@ async def lifespan(app: FastAPI):
# 2. 管理MCP服务的生命周期
mcp_lifespan_context = mcp_app.lifespan(app)
await mcp_lifespan_context.__aenter__()
logger.info("[MCP] MCP服务初始化完成")
logger.info("[Grok2API] 应用启动成功")
logger.info("[MCP] MCP服务端点: /mcp")
try:
yield
@@ -71,8 +72,8 @@ logger.info("[Grok2API] 应用正在启动...")
# 创建FastAPI应用
app = FastAPI(
title="Grok2API",
description="Grok API 转换服务 (包含MCP端点)",
version="1.0.3",
description="Grok API 转换服务",
version="1.3.1",
lifespan=lifespan
)
@@ -85,12 +86,12 @@ app.include_router(models_router, prefix="/v1")
app.include_router(images_router)
app.include_router(admin_router)
# 挂载静态文件(注意:这个应该在API路由之后,避免拦截API请求)
# 挂载静态文件
app.mount("/static", StaticFiles(directory="app/template"), name="template")
@app.get("/")
async def root():
"""根路径 - 重定向到登录页"""
"""根路径"""
from fastapi.responses import RedirectResponse
return RedirectResponse(url="/login")
@@ -104,7 +105,7 @@ async def health_check():
"version": "1.0.3"
}
# 挂载MCP服务器 (最后挂载,避免覆盖其他路由)
# 挂载MCP服务器
app.mount("", mcp_app)
+1 -1
View File
@@ -9,4 +9,4 @@ pydantic==2.12.2
aiofiles==25.1.0
aiomysql==0.2.0
redis==6.4.0
fastmcp>=2.3.0
fastmcp==2.12.4