diff --git a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/base.py b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/base.py index 1a84c497f2addf195bddb7414ddaa547c088bc9d..1489f75307c04e8c3365341b1d06c070b3579fc6 100644 --- a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/base.py +++ b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/base.py @@ -1,3 +1,46 @@ +import logging +import os +import subprocess +from typing import List, Optional + from config.public.base_config_loader import BaseConfig -lang = BaseConfig().get_config().public_config.language \ No newline at end of file +lang = BaseConfig().get_config().public_config.language +logger = logging.getLogger("cmd_executor_tool") +logger.setLevel(logging.INFO) + +def get_cmd_path(cmd: str) -> Optional[str]: + """获取命令绝对路径(简洁实现,避免复杂逻辑)""" + # 优先遍历常见路径(OpenEuler默认路径) + common_paths = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"] + for path in common_paths: + cmd_path = os.path.join(path, cmd) + if os.path.exists(cmd_path) and os.access(cmd_path, os.X_OK): + return cmd_path + # 路径不存在返回None + logger.warning(f"命令不存在:{cmd}(未在常见路径中找到)") + return None + +def run_cmd(cmd: List[str]) -> Optional[str]: + """执行命令(精简异常处理,只捕获关键错误)""" + if cmd[0] == "rm": + logger.warning(f"cmd_executor_tool禁止执行{cmd[0]}") + return None + cmd_path = get_cmd_path(cmd[0]) + if not cmd_path: + return None # 命令不存在直接返回None + cmd[0] = cmd_path # 替换为绝对路径 + + try: + logger.info(f"执行命令:{' '.join(cmd)}") + result = subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + text=True, check=True, timeout=10 + ) + return result.stdout.strip() + except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e: + logger.error(f"命令执行失败:{e.stderr.strip() or str(e)}") + return None + except Exception as e: + logger.error(f"系统调用异常:{str(e)}") + return None \ No newline at end of file diff --git a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/tool.py b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/tool.py index 985b4b571ddb3563a87d97021c1ba782e67b3e60..6ef57018fd9df2d5be74275238f3a457a5b79aa5 100644 --- a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/tool.py +++ b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/cmd_executor_tool/tool.py @@ -3,6 +3,8 @@ from typing import Union, Optional import subprocess from config.public.base_config_loader import BaseConfig,LanguageEnum +from servers.oe_cli_mcp_server.mcp_tools.base_tools.proc_tool.base import run_cmd + # Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. @@ -34,7 +36,7 @@ async def cmd_executor_tool( if not command: response["message"] = "请提供需要执行的命令" if lang == LanguageEnum.ZH else "please give me the command to execute" return response - + command_list = command.split(" ") # -------------------------- 超时时间配置与处理 -------------------------- # 定义常见指令的默认超时时间(秒),可根据需求扩展 cmd_timeout_map = { @@ -83,16 +85,9 @@ async def cmd_executor_tool( def local_exec_sync(): """同步执行本地命令,返回执行结果和错误信息""" try: - result = subprocess.run( - command, - shell=True, - check=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) + result = run_cmd(command_list) # 执行成功,返回输出内容 - return True, result.stdout.strip(), "" + return True, result, "" except subprocess.CalledProcessError as e: # 命令执行返回非0,返回错误信息 return False, "", e.stderr.strip() diff --git a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/base.py b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/base.py index 7b3c1e23f9511c9c5a212082ea62f1cdaaedab20..5311a23d3cd59b9174bb85b3cff1278d212edd5c 100644 --- a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/base.py +++ b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/base.py @@ -97,9 +97,9 @@ class ProcessManager: return zh if self.zh else en # ---------- 查:进程查询(核心功能,无多余嵌套) ---------- - def list_all_procs(self) -> List[Dict]: + def list_all_procs(self,num: Optional[int] = None) -> List[Dict]: """列出所有进程(精简解析逻辑)""" - output = run_cmd(["ps", "aux"]) + output = run_cmd(["ps", "aux","--sort=-%cpu"]) if not output: return [{"error": self._msg("ps命令执行失败", "ps command failed")}] @@ -118,6 +118,7 @@ class ProcessManager: if key in proc: proc[key] = float(proc[key]) if "." in proc[key] else int(proc[key]) procs.append(proc) + procs = procs[:num] return procs def find_proc(self, name: Optional[str] = None, pid: Optional[int] = None) -> List[Dict]: @@ -213,6 +214,7 @@ class ProcessManager: def exec_batch( self, actions: List[ProcActionEnum], + proc_list_num: Optional[int] = None, proc_name: Optional[str] = None, pid: Optional[int] = None, service_name: Optional[str] = None @@ -220,7 +222,7 @@ class ProcessManager: batch_result = {} # 操作映射(减少if-else) action_map = { - ProcActionEnum.LIST: self.list_all_procs, + ProcActionEnum.LIST: lambda :self.list_all_procs(num=proc_list_num), ProcActionEnum.FIND: lambda: self.find_proc(name=proc_name, pid=pid), ProcActionEnum.STAT: lambda: self.get_proc_stat(pid=pid), ProcActionEnum.START: lambda: self.start_proc(service_name=service_name), diff --git a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/config.json b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/config.json index 978cd9ae9895510bfe7d7fd7b17c9c38d1439af2..d97d11b36182f4e26c9779271390cc2f6de6cb69 100644 --- a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/config.json +++ b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/config.json @@ -1,7 +1,7 @@ { "tools": { "proc_tool": { - "zh": "【进程管理工具】\n功能:支持进程的查看、启动、停止、强制终止等管理操作(基于ps/systemctl/kill命令)\n\n【核心提示】\n1. 操作类型(proc_actions)为枚举值列表,支持多选,可选枚举值及对应参数:\n - 查类:\n · list:所有进程(无需额外参数)\n · find:按名称/PID查询(需传proc_name或pid)\n · stat:进程资源占用(需传pid)\n - 启类:\n · start:启动服务(需传service_name,对应systemd服务名)\n · restart:重启服务(需传service_name)\n - 停类:\n · stop:停止服务(需传service_name)\n · kill:强制终止进程(需传pid)\n2. 输入格式示例:\n - 批量查询:[\"list\", \"find\"] + proc_name=\"nginx\"\n - 启停服务:[\"stop\", \"start\"] + service_name=\"nginx\"\n3. 语言配置:自动读取系统全局配置,不提供外部接口;\n4. 权限说明:启停/终止进程需root权限。\n\n【枚举类定义(必须遵守)】\n- ProcActionEnum(进程操作枚举):list / find / stat / start / restart / stop / kill\n\n【参数详情】\n- proc_actions:进程操作列表(必填,枚举值见上方)\n- proc_name:进程名称(find操作必填)\n- pid:进程PID(find/stat/kill操作必填,正整数)\n- service_name:服务名称(start/restart/stop操作必填,对应systemd服务名)\n\n【返回值说明】\n- success:操作结果(True=成功,False=失败)\n- message:操作信息/错误提示(自动切换中英文)\n- result:操作结果(查类返回结构化列表/字典,启/停类返回命令日志)\n- target:执行目标(固定127.0.0.1)\n- proc_actions:已执行的操作列表", + "zh": "【进程管理工具】\n功能:支持进程的查看、启动、停止、强制终止等管理操作(基于ps/systemctl/kill命令)\n\n【核心提示】\n1. 操作类型(proc_actions)为枚举值列表,支持多选,可选枚举值及对应参数:\n - 查类:\n · list:所有进程(按照cpu使用率降序输出)(可传入proc_list_num来调整需要输出的进程数,默认20)\n · find:按名称/PID查询(需传proc_name或pid)\n · stat:进程资源占用(需传pid)\n - 启类:\n · start:启动服务(需传service_name,对应systemd服务名)\n · restart:重启服务(需传service_name)\n - 停类:\n · stop:停止服务(需传service_name)\n · kill:强制终止进程(需传pid)\n2. 输入格式示例:\n - 批量查询:[\"list\", \"find\"] + proc_name=\"nginx\"\n - 启停服务:[\"stop\", \"start\"] + service_name=\"nginx\"\n3. 语言配置:自动读取系统全局配置,不提供外部接口;\n4. 权限说明:启停/终止进程需root权限。\n\n【枚举类定义(必须遵守)】\n- ProcActionEnum(进程操作枚举):list / find / stat / start / restart / stop / kill\n\n【参数详情】\n- proc_actions:进程操作列表(必填,枚举值见上方)\n- proc_list_num:list输出进程数量(list操作选填,默认值20,int类型的正整数)\n- proc_name:进程名称(find操作必填)\n- pid:进程PID(find/stat/kill操作必填,正整数)\n- service_name:服务名称(start/restart/stop操作必填,对应systemd服务名)\n\n【返回值说明】\n- success:操作结果(True=成功,False=失败)\n- message:操作信息/错误提示(自动切换中英文)\n- result:操作结果(查类返回结构化列表/字典,启/停类返回命令日志)\n- target:执行目标(固定127.0.0.1)\n- proc_actions:已执行的操作列表", "en": "【Process Management Tool】\nFunction: Supports process management (view/start/stop/force terminate) via ps/systemctl/kill commands\n\n【Core Guidelines】\n1. Proc actions (proc_actions) is an enum list, supports multiple selection. Enum values and required parameters:\n - Query:\n · list: All processes (no extra params)\n · find: Query by name/PID (requires proc_name or pid)\n · stat: Process resource usage (requires pid)\n - Start:\n · start: Start service (requires service_name, systemd service name)\n · restart: Restart service (requires service_name)\n - Stop:\n · stop: Stop service (requires service_name)\n · kill: Force terminate process (requires pid)\n2. Input examples:\n - Batch query: [\"list\", \"find\"] + proc_name=\"nginx\"\n - Start/stop service: [\"stop\", \"start\"] + service_name=\"nginx\"\n3. Language config: Auto-read global system config, no external interface;\n4. Permission note: Start/stop/terminate requires root privileges.\n\n【Enum Class Definition (Must Follow)】\n- ProcActionEnum (Proc Action Enum): list / find / stat / start / restart / stop / kill\n\n【Parameter Details】\n- proc_actions: Proc action list (required, enum values see above)\n- proc_name: Proc name (required for find)\n- pid: Proc PID (required for find/stat/kill, positive integer)\n- service_name: Service name (required for start/restart/stop, systemd service name)\n\n【Return Value Explanation】\n- success: Operation result (True=success, False=failure)\n- message: Operation info/error prompt (auto-switch between Chinese/English)\n- result: Operation result (query returns structured list/dict, start/stop returns command log)\n- target: Execution target (fixed 127.0.0.1)\n- proc_actions: Executed action list" } } diff --git a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/tool.py b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/tool.py index 82ccbc6847cddb79cd6af786e22a06fb2823a7f0..f631570a8e6631d48f6860750bb42a2dce8743c9 100644 --- a/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/tool.py +++ b/mcp_center/servers/oe_cli_mcp_server/mcp_tools/base_tools/proc_tool/tool.py @@ -13,6 +13,7 @@ def proc_tool( ..., description="进程操作列表(枚举值:list/find/stat/start/restart/stop/kill,支持多选)" ), + proc_list_num: Optional[int] = Field(20, description="list所列出来的进程数量数量"), proc_name: Optional[str] = Field(None, description="进程名称(find操作必填)"), pid: Optional[int] = Field(None, description="进程PID(find/stat/kill操作必填)"), service_name: Optional[str] = Field(None, description="服务名称(start/restart/stop操作必填)") @@ -39,6 +40,7 @@ def proc_tool( batch_result = proc_mgr.exec_batch( actions=parsed_actions, proc_name=proc_name, + proc_list_num = proc_list_num, pid=pid, service_name=service_name )