feat: change the file directory and support authentication
This commit is contained in:
1 parent
c178b988c3
commit
df32f6f1c6
6 files changed
+78
-21
No files matched your search
@@ -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:
|
||||
@@ -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
@@ -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
|
||||
Reference in new issue
Block a user