Files
moss-ai/mcp/didatodolist-mcp/mcp_server.py

141 lines
4.9 KiB
Python
Raw Permalink Normal View History

2025-12-15 22:05:56 +08:00
"""
滴答清单 MCP 服务器定义
"""
import os
import dotenv
from functools import wraps
from fastmcp import FastMCP
# 尝试导入可能的 AuthError如果不存在也没关系
try:
# 假设 fastmcp 提供了特定的认证错误类型
from fastmcp import AuthError
except ImportError:
# 如果没有,使用内置的 PermissionError 作为备选
AuthError = PermissionError
# 导入工具模块
from tools.task_tools import register_task_tools
from tools.project_tools import register_project_tools
from tools.tag_tools import register_tag_tools
from tools.analytics_tools import register_analytics_tools
from tools.goal_tools import register_goal_tools
from tools.official_api import APIError, init_api
from utils.asgi_auth import with_api_key_auth
# 载入 .env若存在
dotenv.load_dotenv()
# --- 鉴权逻辑 ---
EXPECTED_API_KEY = os.environ.get("MCP_API_KEY", "123") # 从环境变量获取,默认'123'
def authenticate_request(context: dict):
"""
认证回调函数尝试检查 API Key
Args:
context: 一个包含请求或会话信息的字典 (假设 fastmcp 提供)
我们需要这个 context 包含访问请求头的方式
Returns:
认证成功时返回会话数据 (例如用户ID)
Raises:
AuthError: 如果认证失败
"""
# !!! 关键点:如何从 context 中获取请求头? !!!
# 假设 context 中有一个 'request' 对象,或者直接有 'headers'
request_headers = context.get("headers", {}) # 这只是一个猜测!
api_key = request_headers.get("x-api-key") # 同样是猜测!
# 尝试认证(日志已禁用)
if api_key != EXPECTED_API_KEY:
# 认证失败API Key 无效或缺失
# 抛出认证错误,告知客户端未授权
raise AuthError("Unauthorized: Invalid API Key") # 或者 PermissionError
# 认证成功
# 认证成功,返回需要在会话中存储的数据
# 这个数据可以在工具函数的 context.session 中访问
return {
"authenticated_user_id": "system", # 可以是任何你想存储的信息
"auth_method": "api_key"
}
def create_server(auth_info=None):
"""
创建并配置MCP服务器
Args:
auth_info: 认证信息字典已弃用token现在通过环境变量传递
Returns:
配置好的MCP服务器实例
"""
# 注意:不再强制要求.env中的token因为我们的架构中token从数据库获取并通过env_vars传递
# 如果环境变量中有token尝试初始化用于独立运行场景
try:
if os.environ.get("DIDA_ACCESS_TOKEN"):
init_api()
# 已初始化官方API 客户端(从环境变量)
else:
# 提示:未检测到 DIDA_ACCESS_TOKEN 环境变量
# 在集成模式下token将由调用方通过环境变量传递
pass
except Exception as e:
# 提示官方API初始化跳过集成模式下正常
pass
try:
# 创建FastMCP服务器简化版不使用authenticate参数
server = FastMCP(
name="didatodolist-mcp",
instructions="滴答清单MCP服务允许AI模型通过MCP协议操作滴答清单待办事项。"
)
# 注册所有工具
register_task_tools(server, auth_info or {})
register_project_tools(server, auth_info or {})
register_tag_tools(server, auth_info or {})
register_analytics_tools(server, auth_info or {})
register_goal_tools(server, auth_info or {})
# ✅ 滴答清单MCP服务初始化成功
return server
except Exception as e:
# ❌ 初始化MCP服务器失败
import traceback
# traceback.print_exc() # 禁用traceback输出避免干扰JSONRPC
raise
# --- 主程序入口 (示例) ---
if __name__ == "__main__":
# 从环境变量或配置文件加载认证信息
dida_auth = {
"token": os.environ.get("DIDA_TOKEN"),
# "email": os.environ.get("DIDA_EMAIL"),
# "password": os.environ.get("DIDA_PASSWORD"),
}
if not dida_auth.get("token"):
print("错误:请设置 DIDA_TOKEN 环境变量")
exit(1)
if not os.environ.get("MCP_API_KEY"):
print("警告:未设置 MCP_API_KEY 环境变量,将使用默认值 '123'")
else:
print(f"MCP_API_KEY 已设置为: {EXPECTED_API_KEY}")
try:
mcp_server = create_server(dida_auth)
# 这里需要根据 fastmcp 的文档来正确运行服务器
print("\n服务器对象已创建。请根据 fastmcp 文档运行服务器。")
print("例如: python -m fastmcp serve your_module:mcp_server --port 3000")
# import uvicorn
# uvicorn.run(mcp_server.app, host="0.0.0.0", port=3000) # 这行可能不正确
except Exception as e:
print(f"启动服务器时出错: {e}")