382 lines
12 KiB
Python
382 lines
12 KiB
Python
"""
|
||
MCP 设备服务
|
||
封装 MCP 设备查询服务的调用,供后端 API 使用
|
||
"""
|
||
|
||
import asyncio
|
||
import json
|
||
import logging
|
||
import os
|
||
from pathlib import Path
|
||
from typing import Optional, Dict, Any, List
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class MCPDeviceService:
|
||
"""MCP 设备服务类"""
|
||
|
||
def __init__(self):
|
||
"""初始化 MCP 设备服务"""
|
||
# 计算 MCP 服务路径
|
||
# 当前文件: app/backend-python/services/mcp_device_service.py
|
||
# 目标路径: mcp/device_query_mcp.py
|
||
current_dir = Path(__file__).parent # app/backend-python/services
|
||
backend_dir = current_dir.parent # app/backend-python
|
||
app_dir = backend_dir.parent # app
|
||
project_root = app_dir.parent # project root
|
||
self.mcp_path = project_root / "mcp" / "device_query_mcp.py"
|
||
|
||
logger.info(f"MCP 服务路径: {self.mcp_path}")
|
||
|
||
if not self.mcp_path.exists():
|
||
logger.warning(f"MCP 服务文件不存在: {self.mcp_path}")
|
||
|
||
# MCP 依赖检查
|
||
self.mcp_available = self._check_mcp_available()
|
||
|
||
def _check_mcp_available(self) -> bool:
|
||
"""检查 MCP 是否可用"""
|
||
# 1. 检查文件是否存在
|
||
if not self.mcp_path.exists():
|
||
logger.error(f"❌ MCP 服务文件不存在: {self.mcp_path}")
|
||
return False
|
||
|
||
# 2. 检查依赖是否已安装
|
||
try:
|
||
from mcp import ClientSession, StdioServerParameters
|
||
from mcp.client.stdio import stdio_client
|
||
logger.info("✅ MCP 依赖检查通过")
|
||
return True
|
||
except ImportError as e:
|
||
logger.error(f"❌ MCP 依赖未安装: {e}")
|
||
return False
|
||
|
||
async def _call_mcp_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
调用 MCP 工具
|
||
|
||
Args:
|
||
tool_name: 工具名称
|
||
arguments: 工具参数
|
||
|
||
Returns:
|
||
工具返回的结果(JSON 格式),如果MCP不可用返回包含错误信息的字典
|
||
"""
|
||
# 预检查:MCP 是否可用
|
||
if not self.mcp_available:
|
||
if not self.mcp_path.exists():
|
||
logger.error(f"开发错误:MCP 服务文件不存在: {self.mcp_path}")
|
||
else:
|
||
logger.error("开发错误:MCP 依赖未安装(pip install fastmcp)")
|
||
|
||
return {
|
||
"success": False,
|
||
"message": "请先检查设备查询服务是否启动。"
|
||
}
|
||
|
||
try:
|
||
from mcp import ClientSession, StdioServerParameters
|
||
from mcp.client.stdio import stdio_client
|
||
|
||
logger.info(f"✅ 调用 MCP 工具: {tool_name}, 参数: {arguments}")
|
||
|
||
# 创建 MCP 客户端
|
||
server_params = StdioServerParameters(
|
||
command="python",
|
||
args=[str(self.mcp_path)],
|
||
)
|
||
|
||
async with stdio_client(server_params) as (read, write):
|
||
async with ClientSession(read, write) as session:
|
||
# 初始化
|
||
await session.initialize()
|
||
|
||
# 调用工具
|
||
result = await session.call_tool(tool_name, arguments=arguments)
|
||
|
||
# 解析结果
|
||
result_text = result.content[0].text if hasattr(result, 'content') else str(result)
|
||
return json.loads(result_text)
|
||
|
||
except ImportError as e:
|
||
logger.error(f"开发错误:MCP 模块未安装: {e}")
|
||
return {
|
||
"success": False,
|
||
"message": "请先检查设备查询服务是否启动。"
|
||
}
|
||
except Exception as e:
|
||
logger.error(f"MCP 服务调用失败: {e}", exc_info=True)
|
||
return {
|
||
"success": False,
|
||
"message": "请先检查设备查询服务是否启动。"
|
||
}
|
||
|
||
def _call_mcp_tool_sync(self, tool_name: str, arguments: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
同步方式调用 MCP 工具
|
||
|
||
Args:
|
||
tool_name: 工具名称
|
||
arguments: 工具参数
|
||
|
||
Returns:
|
||
工具返回的结果(JSON 格式)
|
||
"""
|
||
try:
|
||
# 获取或创建事件循环
|
||
try:
|
||
loop = asyncio.get_event_loop()
|
||
except RuntimeError:
|
||
loop = asyncio.new_event_loop()
|
||
asyncio.set_event_loop(loop)
|
||
|
||
# 运行异步函数
|
||
return loop.run_until_complete(self._call_mcp_tool(tool_name, arguments))
|
||
except Exception as e:
|
||
logger.error(f"同步调用 MCP 工具失败: {e}")
|
||
return None
|
||
|
||
async def get_user_devices(
|
||
self,
|
||
system_user_id: int,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取用户的所有米家设备列表
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
设备列表信息
|
||
"""
|
||
arguments = {"system_user_id": system_user_id}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return await self._call_mcp_tool("get_user_devices", arguments)
|
||
|
||
def get_user_devices_sync(
|
||
self,
|
||
system_user_id: int,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取用户的所有米家设备列表(同步版本)
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
设备列表信息
|
||
"""
|
||
arguments = {"system_user_id": system_user_id}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return self._call_mcp_tool_sync("get_user_devices", arguments)
|
||
|
||
async def get_device_by_name(
|
||
self,
|
||
system_user_id: int,
|
||
device_name: str,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
根据设备名称查询设备信息
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
device_name: 设备名称(支持模糊匹配)
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
匹配的设备信息
|
||
"""
|
||
arguments = {
|
||
"system_user_id": system_user_id,
|
||
"device_name": device_name
|
||
}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return await self._call_mcp_tool("get_device_by_name", arguments)
|
||
|
||
def get_device_by_name_sync(
|
||
self,
|
||
system_user_id: int,
|
||
device_name: str,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
根据设备名称查询设备信息(同步版本)
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
device_name: 设备名称(支持模糊匹配)
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
匹配的设备信息
|
||
"""
|
||
arguments = {
|
||
"system_user_id": system_user_id,
|
||
"device_name": device_name
|
||
}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return self._call_mcp_tool_sync("get_device_by_name", arguments)
|
||
|
||
async def get_device_by_model(
|
||
self,
|
||
system_user_id: int,
|
||
model: str,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
根据设备型号查询设备信息
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
model: 设备型号
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
匹配的设备信息
|
||
"""
|
||
arguments = {
|
||
"system_user_id": system_user_id,
|
||
"model": model
|
||
}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return await self._call_mcp_tool("get_device_by_model", arguments)
|
||
|
||
def get_device_by_model_sync(
|
||
self,
|
||
system_user_id: int,
|
||
model: str,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
根据设备型号查询设备信息(同步版本)
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
model: 设备型号
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
匹配的设备信息
|
||
"""
|
||
arguments = {
|
||
"system_user_id": system_user_id,
|
||
"model": model
|
||
}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return self._call_mcp_tool_sync("get_device_by_model", arguments)
|
||
|
||
async def get_online_devices(
|
||
self,
|
||
system_user_id: int,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取所有在线的设备
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
在线设备信息
|
||
"""
|
||
arguments = {"system_user_id": system_user_id}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return await self._call_mcp_tool("get_online_devices", arguments)
|
||
|
||
def get_online_devices_sync(
|
||
self,
|
||
system_user_id: int,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取所有在线的设备(同步版本)
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
在线设备信息
|
||
"""
|
||
arguments = {"system_user_id": system_user_id}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return self._call_mcp_tool_sync("get_online_devices", arguments)
|
||
|
||
async def get_device_count(
|
||
self,
|
||
system_user_id: int,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取用户的设备统计信息
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
设备统计信息
|
||
"""
|
||
arguments = {"system_user_id": system_user_id}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return await self._call_mcp_tool("get_device_count", arguments)
|
||
|
||
def get_device_count_sync(
|
||
self,
|
||
system_user_id: int,
|
||
server: Optional[str] = None
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取用户的设备统计信息(同步版本)
|
||
|
||
Args:
|
||
system_user_id: 系统用户ID
|
||
server: 服务器区域(可选)
|
||
|
||
Returns:
|
||
设备统计信息
|
||
"""
|
||
arguments = {"system_user_id": system_user_id}
|
||
if server:
|
||
arguments["server"] = server
|
||
|
||
return self._call_mcp_tool_sync("get_device_count", arguments)
|
||
|
||
|
||
# 全局实例
|
||
_mcp_device_service = None
|
||
|
||
|
||
def get_mcp_device_service() -> MCPDeviceService:
|
||
"""获取 MCP 设备服务实例(单例模式)"""
|
||
global _mcp_device_service
|
||
if _mcp_device_service is None:
|
||
_mcp_device_service = MCPDeviceService()
|
||
return _mcp_device_service
|
||
|