File size: 3,664 Bytes
fbd9d3d e0ea7df fbd9d3d e0ea7df fbd9d3d e0ea7df fbd9d3d cc826a1 e0ea7df fbd9d3d e0ea7df 0d8512e fbd9d3d e0ea7df fbd9d3d e0ea7df fbd9d3d e0ea7df fbd9d3d e0ea7df cc826a1 e0ea7df fbd9d3d e0ea7df cc826a1 e0ea7df fbd9d3d e0ea7df 0d8512e e0ea7df fbd9d3d 0d8512e e0ea7df 0d8512e e0ea7df 0d8512e cc826a1 0d8512e cc826a1 e0ea7df 0d8512e fbd9d3d e0ea7df | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | """
浏览器MCP插件主模块(v3.0 纯 Lightpanda 透传)。
提供 28 个通用浏览器 MCP tool,对任意环境 agent 暴露与 Lightpanda 上游一致的
浏览器能力。纯 Lightpanda 单后端,单例长驻子进程。
"""
import logging
logger = logging.getLogger(__name__)
PLUGIN_VERSION = "3.0.0"
# 上游工具数(与 tools_meta 一致,供状态展示)
TOOLS_COUNT = 28
class BrowserMCPPlugin:
"""浏览器MCP插件。"""
def __init__(self):
self.name = "browser"
self.version = PLUGIN_VERSION
self.enabled = False
self._init_error = None
# 缓存二进制探测结果,避免 check_readiness / get_status 重复探测
self._binary_check_cache = None
def on_enable(self):
"""插件启用时调用。不预启动子进程——首次工具调用时按需拉起。"""
self.enabled = True
logger.info(f"{self.name} v{self.version} 已启用(lightpanda 单后端,懒启动)")
def on_disable(self):
"""插件禁用时调用。best-effort 关闭子进程。"""
self.enabled = False
try:
from plugins.browser.browser.client import LightpandaClient
LightpandaClient.instance().close_sync()
except Exception as e:
logger.warning(f"{self.name} 关闭子进程失败: {e}")
logger.info(f"{self.name} 已禁用")
def get_status(self) -> dict:
"""获取插件状态。"""
from plugins.browser.browser.client import LightpandaClient
process_alive = False
try:
process_alive = LightpandaClient.instance().process_alive
except Exception:
process_alive = False
return {
"name": self.name,
"version": self.version,
"enabled": self.enabled,
"backend": "lightpanda",
"binary_check": self._get_binary_check(),
"process_alive": process_alive,
"tools_count": TOOLS_COUNT,
"error": self._init_error,
}
def check_readiness(self) -> dict:
"""readiness hook,plugin_manager 可选调用。
Lightpanda 二进制不可用时返回 ok=False → DEPENDENCY_ERROR;
任意探测异常都返回 ok=True(不阻断其他插件)。
"""
try:
from plugins.browser.browser.binary_locator import locate_lightpanda
if self._binary_check_cache is None:
self._binary_check_cache = locate_lightpanda()
check = self._binary_check_cache
return {
"ok": check.available,
"reason": None if check.available else (check.error or "lightpanda unavailable"),
"details": {
"binary_path": check.path,
"version": check.version,
"source": check.source,
"platform": check.platform,
},
}
except Exception as e:
# 探测本身失败不应阻断插件运行
logger.warning(f"{self.name} readiness check 异常: {e}")
return {"ok": True, "reason": None, "details": {}}
def _get_binary_check(self) -> dict:
"""获取二进制探测结果(dict 形式,带内存缓存)。"""
if self._binary_check_cache is None:
from plugins.browser.browser.binary_locator import locate_lightpanda
self._binary_check_cache = locate_lightpanda()
return self._binary_check_cache.to_dict()
# 创建插件实例(plugin_loader 按 *Plugin 命名查找)
plugin = BrowserMCPPlugin()
|