diff --git a/servers/devkit_mcp/src/devkit_mcp.py b/servers/devkit_mcp/src/devkit_mcp.py index 8a7264d1d6ee56128937b1b9c6ffdeef370c643e..2cb0f4efdb56039cff302fdaaea93d18388289ee 100644 --- a/servers/devkit_mcp/src/devkit_mcp.py +++ b/servers/devkit_mcp/src/devkit_mcp.py @@ -1,5 +1,10 @@ +import os import subprocess import argparse +import collections +import logging +import os +import time from typing import Optional, Dict from mcp.server.fastmcp import FastMCP from pydantic import Field @@ -10,6 +15,16 @@ args, _ = parser.parse_known_args() mcp = FastMCP("鲲鹏DevKit工具是一款涵盖系统/应用迁移、亲和分析、编译调试和调优诊断等的工具集") +logger = logging.getLogger(__name__) +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(), + logging.FileHandler("/Images/mcp.log",mode='a',encoding='utf-8') + ] +) + @mcp.tool() def analysis_python( task: str = Field(default="hotspot", description="性能分析任务类型,如:hotspot"), @@ -1748,6 +1763,151 @@ if __name__ == "__main__": "retry": False } + @mcp.tool() + def devkit_kat_mysql_tune( + help: bool = Field(default=False, description="显示帮助信息") + ) -> Dict: + """帮我对mysql进行自动调优""" + try: + # 创建必要的目录结构 + required_dirs = [ + '/Images/lib/mysql', + '/Images/log/mysql', + '/run/mysqld' + ] + + for dir_path in required_dirs: + try: + subprocess.run(['mkdir', '-p', dir_path], check=True) + subprocess.run(['chown', 'mysql:mysql', dir_path], check=True) + logger.info(f"Created and set permissions for directory: {dir_path}") + except subprocess.CalledProcessError as e: + logger.warning(f"Failed to create/set permissions for {dir_path}: {str(e)}") + return { + "error": f"Failed to setup required directories: {str(e)}", + "required_dirs": required_dirs + } + + # 检查MySQL服务状态 + try: + subprocess.run(['systemctl', 'start', 'mysqld'], check=True) + subprocess.run(['systemctl', 'enable', 'mysqld'], check=True) + logger.info("MySQL service started and enabled") + except subprocess.CalledProcessError as e: + logger.error(f"Failed to start MySQL service: {str(e)}") + return {"error": f"Failed to start MySQL service: {str(e)}"} + + # 清除root密码 + try: + subprocess.run(['mysqladmin', '-u', 'root', 'password', ''], check=True) + logger.info("Cleared MySQL root password") + except subprocess.CalledProcessError as e: + logger.warning(f"Failed to clear MySQL root password: {str(e)}") + return {"error": f"Failed to clear MySQL root password: {str(e)}"} + + # 验证免密登录 + try: + result = subprocess.run( + ['mysql', '-u', 'root', '-e', 'SELECT 1'], + capture_output=True, + text=True + ) + if result.returncode != 0: + raise subprocess.CalledProcessError(result.returncode, result.args) + logger.info("Verified passwordless login to MySQL") + except subprocess.CalledProcessError as e: + logger.error(f"Failed to verify passwordless login: {str(e)}") + return {"error": f"Failed to verify passwordless login: {str(e)}"} + + # 停止MySQL服务 + try: + subprocess.run(['systemctl', 'stop', 'mysqld'], check=True) + logger.info("MySQL service stopped successfully") + + # 验证服务已停止 + result = subprocess.run( + ['systemctl', 'is-active', 'mysqld'], + capture_output=True, + text=True + ) + time.sleep(30) + if result.stdout.strip() == 'active': + logger.error("MySQL service is still running after stop command") + return {"error": "Failed to stop MySQL service"} + + except subprocess.CalledProcessError as e: + logger.error(f"Failed to stop MySQL service: {str(e)}") + return {"error": f"Failed to stop MySQL service: {str(e)}"} + + # 检查MySQL配置文件 + mysql_conf = '/etc/my.cnf.d/mysql-server.cnf' + if not os.path.exists(mysql_conf): + logger.error(f"MySQL config file not found at {mysql_conf}") + return {"error": f"MySQL config file not found at {mysql_conf}"} + + # 执行调优命令 + cmd = [ + 'devkit', 'kat', 'train', + '-t', '/opt/mcp-servers/servers/devkit_mcp/kat_template/template_MySQL/task_MySQL_System.json', + '-p', '/opt/mcp-servers/servers/devkit_mcp/kat_template/template_MySQL/param_MySQL_System.json', + '-l', '0' + ] + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1, + universal_newlines=True + ) + + # 缓存最后100行输出 + output_buffer = collections.deque(maxlen=100) + error_buffer = collections.deque(maxlen=100) + + def read_output(stream, buffer): + for line in stream: + buffer.append(line.strip()) + logging.debug(line, end='') # 实时打印输出 + + # 创建线程分别读取stdout和stderr + from threading import Thread + stdout_thread = Thread(target=read_output, args=(process.stdout, output_buffer)) + stderr_thread = Thread(target=read_output, args=(process.stderr, error_buffer)) + + stdout_thread.start() + stderr_thread.start() + + # 等待进程结束 + process.wait() + stdout_thread.join() + stderr_thread.join() + + # 准备返回结果 + result = { + "command": " ".join(cmd), + "status": "completed" if process.returncode == 0 else "failed", + "return_code": process.returncode, + "stdout": "\n".join(output_buffer), + "stderr": "\n".join(error_buffer), + "last_100_lines": list(output_buffer), # 返回最后100行 + "output": "\n".join(output_buffer) # 兼容旧版本 + } + + if process.returncode != 0: + result["error"] = "\n".join(error_buffer) + + return result + + except subprocess.CalledProcessError as e: + return { + "error": e.stderr if e.stderr else e.output, + "command": " ".join(cmd) if 'cmd' in locals() else None, + "return_code": e.returncode + } + except Exception as e: + return {"error": str(e)} + @mcp.tool() def devkit_kat( task: Optional[str] = Field(default=None, description="任务类型: analysis/advisor/doctor/porting"), @@ -1770,7 +1930,7 @@ if __name__ == "__main__": "missing_params": ["task"], "suggestions": ["analysis", "advisor", "doctor", "porting"] } - + # 构建命令 cmd = ['devkit', 'kat', task] if args: diff --git a/servers/unpack_rpm_tar_mcp/mcp-rpm.yaml b/servers/unpack_rpm_tar_mcp/mcp-rpm.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5dd2d06421c596dec2ce0bb8d72b500d5d381e75 --- /dev/null +++ b/servers/unpack_rpm_tar_mcp/mcp-rpm.yaml @@ -0,0 +1,20 @@ +name: "unpack-rpm-tar" +summary: "MCP server for unpacking RPM and tar archives" +description: | + Provides MCP tools for unpacking RPM packages and tar archives. + +dependencies: + system: + - python3 + - uv + - python3-mcp + - rpm + - tar + - gzip + +files: + required: + - mcp_config.json + - src/server.py + optional: + - src/requirements.txt \ No newline at end of file diff --git a/servers/unpack_rpm_tar_mcp/mcp_config.json b/servers/unpack_rpm_tar_mcp/mcp_config.json new file mode 100644 index 0000000000000000000000000000000000000000..4c52146c062a2aeb9ba8c8dee1de2ac70fc62705 --- /dev/null +++ b/servers/unpack_rpm_tar_mcp/mcp_config.json @@ -0,0 +1,20 @@ +{ + "mcpServers": { + "unpack_rpm_tar_mcp": { + "command": "uv", + "args": [ + "--directory", + "/opt/mcp-servers/servers/unpack_rpm_tar_mcp", + "run", + "src/server.py" + ], + "disabled": false, + "autoApprove": [], + "alwaysAllow": [ + "create_tar", + "extract_tar", + "rpm_unpack" + ] + } + } +} \ No newline at end of file diff --git a/servers/unpack_rpm_tar_mcp/src/requirements.txt b/servers/unpack_rpm_tar_mcp/src/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd089c61509a909fddb46e5ff7e0756a8365b4ad --- /dev/null +++ b/servers/unpack_rpm_tar_mcp/src/requirements.txt @@ -0,0 +1 @@ +mcp>=1.0.0 \ No newline at end of file diff --git a/servers/unpack_rpm_tar_mcp/src/server.py b/servers/unpack_rpm_tar_mcp/src/server.py new file mode 100644 index 0000000000000000000000000000000000000000..37ddeaeb37ce3e76df77d4fe79ff3d8b179491d2 --- /dev/null +++ b/servers/unpack_rpm_tar_mcp/src/server.py @@ -0,0 +1,64 @@ +import tarfile +import os +import subprocess +from pathlib import Path +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP("tar压缩和解压工具") + +@mcp.tool() +def create_tar(source_path: str, output_path: str) -> str: + """将文件或目录打包为tar.gz压缩包 + + Args: + source_path: 要压缩的文件或目录路径 + output_path: 输出的tar.gz文件路径 + + Returns: + 操作结果信息 + """ + try: + with tarfile.open(output_path, "w:gz") as tar: + tar.add(source_path, arcname=os.path.basename(source_path)) + return f"成功创建压缩包: {output_path}" + except Exception as e: + return f"创建压缩包失败: {str(e)}" + +@mcp.tool() +def extract_tar(tar_path: str, output_dir: str) -> str: + """解压tar.gz压缩包到指定目录 + + Args: + tar_path: 要解压的tar.gz文件路径 + output_dir: 解压目标目录 + + Returns: + 操作结果信息 + """ + try: + with tarfile.open(tar_path) as tar: + tar.extractall(output_dir) + return f"成功解压到目录: {output_dir}" + except Exception as e: + return f"解压失败: {str(e)}" + +@mcp.tool() +def rpm_unpack(rpm_path: str, output_dir: str) -> str: + """解压RPM包到指定目录 + + Args: + rpm_path: RPM文件路径 + output_dir: 解压目标目录 + + Returns: + 操作结果信息 + """ + try: + cmd = f"rpm2cpio {rpm_path} | cpio -idm -D {output_dir}" + subprocess.run(cmd, shell=True, check=True) + return f"成功解压RPM包到: {output_dir}" + except subprocess.CalledProcessError as e: + return f"解压RPM包失败: {str(e)}" + +if __name__ == "__main__": + mcp.run() \ No newline at end of file diff --git a/servers/wget_mcp/mcp-rpm.yaml b/servers/wget_mcp/mcp-rpm.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bd2c02e7a23f8ee97dcd9b270ebc69b6de4e326c --- /dev/null +++ b/servers/wget_mcp/mcp-rpm.yaml @@ -0,0 +1,18 @@ +name: "wget-downloader" +summary: "MCP server for file downloading using wget" +description: | + Provides MCP tools for downloading files from URLs using wget command. + +dependencies: + system: + - python3 + - uv + - python3-mcp + - wget + +files: + required: + - mcp_config.json + - src/server.py + optional: + - src/requirements.txt \ No newline at end of file diff --git a/servers/wget_mcp/mcp_config.json b/servers/wget_mcp/mcp_config.json new file mode 100644 index 0000000000000000000000000000000000000000..2fc1c06f6fce96724b8a92e6e9c6862fa8f15930 --- /dev/null +++ b/servers/wget_mcp/mcp_config.json @@ -0,0 +1,18 @@ +{ + "mcpServers": { + "wget_mcp": { + "command": "uv", + "args": [ + "--directory", + "/opt/mcp-servers/servers/wget_mcp", + "run", + "src/server.py" + ], + "disabled": false, + "autoApprove": [], + "alwaysAllow": [ + "download_file" + ] + } + } +} \ No newline at end of file diff --git a/servers/wget_mcp/src/requirements.txt b/servers/wget_mcp/src/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..7211e49a1325ab90f08e21ad5d863873d7079c3d --- /dev/null +++ b/servers/wget_mcp/src/requirements.txt @@ -0,0 +1 @@ +mcp>=1.9.4 \ No newline at end of file diff --git a/servers/wget_mcp/src/server.py b/servers/wget_mcp/src/server.py new file mode 100644 index 0000000000000000000000000000000000000000..09794fcd780b00b5aebf0a0bc2b8ac733e5118b6 --- /dev/null +++ b/servers/wget_mcp/src/server.py @@ -0,0 +1,40 @@ +import os +import subprocess +from pathlib import Path +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP("wget下载工具") + +@mcp.tool() +def download_file(url: str, output_path: str = None) -> str: + """下载指定URL的文件 + + Args: + url: 要下载的URL地址 + output_path: 输出的文件路径(可选) + + Returns: + 操作结果信息 + """ + try: + cmd = ["wget", url] + if output_path: + cmd.extend(["-O", output_path]) + + result = subprocess.run( + cmd, + check=True, + capture_output=True, + text=True + ) + + if output_path: + return f"成功下载文件到: {output_path}" + else: + filename = url.split('/')[-1] + return f"成功下载文件: {filename}" + except subprocess.CalledProcessError as e: + return f"下载失败: {e.stderr or str(e)}" + +if __name__ == "__main__": + mcp.run() \ No newline at end of file