Skip to main content
Glama

YST KPI Daily Report Collector

by Xuzan9396
server.py12 kB
""" YST KPI Report Collector MCP Service 使用 FastMCP 采集 KPI 系统日报数据 集成浏览器自动化登录功能 """ import sys import platform import asyncio import os # 导入 Playwright 浏览器路径 hook(打包时需要) try: import playwright_hook except ImportError: pass # 开发模式下可能不存在 # Windows 兼容性:强制使用 UTF-8 编码 if platform.system() == 'Windows': # 设置环境变量强制使用 UTF-8 os.environ['PYTHONUTF8'] = '1' # 设置 stdout 和 stderr 为 UTF-8 import io if hasattr(sys.stdout, 'reconfigure'): sys.stdout.reconfigure(encoding='utf-8', errors='replace') sys.stderr.reconfigure(encoding='utf-8', errors='replace') else: # Python 3.6 兼容 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace') # 在 Windows 上,stdio 需要使用 SelectorEventLoop if sys.version_info >= (3, 8): # Python 3.8+ 默认使用 ProactorEventLoop,需要改为 SelectorEventLoop asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) from fastmcp import FastMCP from report_collector import ReportCollector, safe_text from cookie_manager import CookieManager from browser_login import BrowserLogin from logger import logger # 创建 MCP 服务 mcp = FastMCP("yst-mcp") @mcp.tool() async def collect_reports(start_month: str, end_month: str, output_file: str = None, auto_login: bool = False) -> str: """ 采集指定月份范围的日报数据 ⚠️ 重要:使用前请先确保已登录! 推荐流程: 1. 先调用 check_login_status 检查登录状态 2. 如果未登录,调用 browser_login 进行登录 3. 登录成功后,再调用本工具采集数据 这样可以避免采集过程被登录流程阻塞。 Args: start_month: 起始月份,格式 YYYY-MM (例如: 2025-07) end_month: 结束月份,格式 YYYY-MM (例如: 2025-09) output_file: 输出文件路径(可选,默认为 ~/.yst_mcp/output/new.md 或项目目录下 data/new.md) auto_login: 未登录时是否自动启动浏览器登录(默认 False,不推荐设为 True) Returns: 采集结果描述 """ collector = ReportCollector() cookie_manager = CookieManager() try: # 检查是否有保存的 Cookie if cookie_manager.has_cookies(): collector.load_saved_cookies() # 检查登录状态 if not collector.check_login_status(): if auto_login: print(safe_text("❌ 未登录,正在启动浏览器...")) # 启动浏览器登录 browser_login = BrowserLogin() if await browser_login.launch_persistent_browser(): # 重新加载 Cookie collector.load_saved_cookies() else: return safe_text("❌ 登录失败或超时,请重试") else: return safe_text( "❌ 未登录或 Cookie 已过期\n\n" "请使用以下方法之一:\n" "1. 调用 browser_login 工具启动浏览器登录\n" "2. 将 auto_login 参数设置为 true,自动打开浏览器" ) # 执行采集 result = await collector.collect(start_month, end_month, output_file) return result except Exception as e: return f"采集失败: {str(e)}" @mcp.tool() async def browser_login(use_persistent: bool = True, timeout: int = 300) -> str: """ 启动浏览器进行登录 ✅ 推荐使用流程: 1. 调用此工具启动浏览器 2. 在浏览器中完成 Google 登录(约1分钟) 3. 登录成功后,调用 collect_reports 采集数据 工作流程: 1. 打开浏览器窗口 2. 等待您完成 Google OAuth 登录 3. 自动提取并保存 Cookie 4. 保存浏览器会话 Args: use_persistent: 是否使用持久化浏览器上下文(推荐,默认 True) timeout: 登录超时时间(秒),默认 300 秒(5 分钟) Returns: 登录结果 """ try: logger.info("=" * 60) logger.info("browser_login 工具被调用") logger.info(f"use_persistent: {use_persistent}, timeout: {timeout}") logger.info("=" * 60) print(safe_text("🌐 正在启动浏览器登录...")) login = BrowserLogin() if use_persistent: logger.info("使用持久化浏览器上下文") success = await login.launch_persistent_browser() else: logger.info("使用临时浏览器上下文") success = await login.launch_browser_for_login(headless=False, timeout=timeout) if success: logger.info("✓ 浏览器登录成功") return safe_text( "✅ 登录成功!\n\n" "Cookie 已保存,现在可以使用 collect_reports 采集数据了" ) else: logger.error("✗ 浏览器登录失败") return safe_text( "❌ 登录失败或超时\n\n" "请检查:\n" "1. 浏览器是否正常弹出\n" "2. 是否完成了 Google 登录\n" "3. 查看日志文件获取详细信息" ) except Exception as e: logger.exception("browser_login 执行出错:") return safe_text(f"❌ 启动失败: {str(e)}\n\n请查看日志文件获取详细错误信息") @mcp.tool() async def save_cookies_from_browser(cookie_string: str) -> str: """ 保存浏览器 Cookie(用于首次登录) 使用方法: 1. 使用 chrome_devtools_mcp 登录 https://kpi.drojian.dev 2. 登录成功后,从浏览器复制 Cookie 字符串 3. 调用此工具保存 Cookie Args: cookie_string: Cookie 字符串,格式如 "name1=value1; name2=value2" 或者完整的 curl 命令中的 -b 参数内容 Returns: 保存结果 """ collector = ReportCollector() try: # 加载 Cookie if collector.load_cookies_from_string(cookie_string): # 保存到文件 if collector.save_current_cookies(): return safe_text("✓ Cookie 保存成功!现在可以使用 collect_reports 工具采集数据了") else: return safe_text("❌ Cookie 保存失败") else: return safe_text("❌ Cookie 格式错误") except Exception as e: return safe_text(f"保存失败: {str(e)}") @mcp.tool() async def check_login_status() -> str: """ 检查当前登录状态(建议第一步调用) ✅ 推荐工作流程: 1. 首先调用此工具检查登录状态 2. 如果返回"未登录",则调用 browser_login 进行登录 3. 登录成功后,调用 collect_reports 采集数据 Returns: 登录状态信息: - "✓ 已登录,Cookie 有效" -> 可以直接采集数据 - "❌ Cookie 已过期" -> 需要调用 browser_login 重新登录 - "❌ 未找到保存的 Cookie" -> 需要调用 browser_login 首次登录 """ collector = ReportCollector() try: # 尝试加载已保存的 Cookie if collector.cookie_manager.has_cookies(): collector.load_saved_cookies() # 检查登录状态 if collector.check_login_status(): return safe_text("✓ 已登录,Cookie 有效") else: return safe_text("❌ Cookie 已过期,请重新登录并保存 Cookie") else: return safe_text("❌ 未找到保存的 Cookie,请先使用 save_cookies_from_browser 工具保存登录信息") except Exception as e: return safe_text(f"检查失败: {str(e)}") @mcp.tool() async def check_playwright_installation() -> str: """ 检查 Playwright 浏览器驱动安装状态 Returns: 安装状态信息 """ import subprocess import sys try: logger.info("检查 Playwright 安装状态") # 检查 Playwright 模块 try: import playwright playwright_version = playwright.__version__ logger.info(f"Playwright 模块已安装,版本: {playwright_version}") except ImportError: return safe_text( "❌ Playwright 模块未安装\n\n" "请运行以下命令安装:\n" "pip install playwright\n" "playwright install chromium" ) # 检查浏览器驱动 result_text = safe_text(f"✓ Playwright 模块已安装 (v{playwright_version})\n\n") # 尝试检查浏览器安装 try: # 运行 playwright install --dry-run 检查浏览器状态 result = subprocess.run( [sys.executable, "-m", "playwright", "install", "--dry-run", "chromium"], capture_output=True, text=True, timeout=10 ) logger.debug(f"playwright install --dry-run 输出: {result.stdout}") if "is already installed" in result.stdout or "Skipping" in result.stdout: result_text += safe_text("✓ Chromium 浏览器驱动已安装\n\n") result_text += "系统状态:正常\n" result_text += "\n如果浏览器仍无法弹出,请检查:\n" result_text += "1. 防火墙/杀毒软件是否阻止\n" result_text += "2. 查看详细日志文件" else: result_text += safe_text("⚠ Chromium 浏览器驱动可能未安装\n\n") result_text += "请运行以下命令安装:\n" result_text += "playwright install chromium\n\n" result_text += "或在 Windows PowerShell 中:\n" result_text += "python -m playwright install chromium" except subprocess.TimeoutExpired: logger.warning("playwright install 命令超时") result_text += safe_text("⚠ 无法检查浏览器驱动状态(命令超时)\n\n") result_text += "建议手动运行:playwright install chromium" except Exception as e: logger.error(f"检查浏览器驱动失败: {e}") result_text += safe_text(f"⚠ 无法检查浏览器驱动: {str(e)}\n\n") result_text += "建议手动运行:playwright install chromium" return result_text except Exception as e: logger.exception("检查 Playwright 安装状态出错:") return safe_text(f"❌ 检查失败: {str(e)}") @mcp.tool() async def clear_saved_cookies() -> str: """ 清除已保存的 Cookie Returns: 清除结果 """ manager = CookieManager() try: if manager.clear_cookies(): return safe_text("✓ Cookie 已清除") else: return safe_text("❌ 清除失败") except Exception as e: return safe_text(f"清除失败: {str(e)}") if __name__ == "__main__": try: logger.info("=" * 60) logger.info("YST MCP Server 启动") logger.info(f"平台: {platform.system()} {platform.release()}") logger.info(f"Python: {sys.version}") if platform.system() == 'Windows': logger.info("检测到 Windows 系统,已设置 SelectorEventLoop 策略") # 记录当前事件循环策略 policy = asyncio.get_event_loop_policy() logger.info(f"当前事件循环策略: {type(policy).__name__}") logger.info("=" * 60) mcp.run() except Exception as e: logger.exception("MCP 服务器启动失败:") raise

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/Xuzan9396/yst_mcp'

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