From 24b93433ebd4ec04e8fd13e8acece9207796b0e0 Mon Sep 17 00:00:00 2001 From: dingjiahuichina Date: Thu, 10 Apr 2025 20:46:43 +0800 Subject: [PATCH] =?UTF-8?q?opt:=20=E4=BC=98=E5=8C=96oeDeploy=20MCP?= =?UTF-8?q?=EF=BC=8C=E6=96=87=E5=AD=97=E8=A1=A8=E8=BF=B0=E6=9B=B4=E5=87=86?= =?UTF-8?q?=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oedp-mcp/README.md | 14 ++-- oedp-mcp/mcp-make-oedp-plugin.py | 15 ++--- oedp-mcp/mcp-oedp.py | 110 ++++++++++++++++++++++++++----- 3 files changed, 107 insertions(+), 32 deletions(-) diff --git a/oedp-mcp/README.md b/oedp-mcp/README.md index bd42923..2d54138 100644 --- a/oedp-mcp/README.md +++ b/oedp-mcp/README.md @@ -7,7 +7,7 @@ oeDeploy 目前提供了两个 MCP Server ## 1. 环境准备 -安装 python 依赖。为了更加直观,当前示例使用 `pip`安装到系统的 python 目录,实际上更加推荐 `uv`安装到虚拟环境。 +安装 python 依赖。为了更加直观,当前示例使用`pip`安装到系统的 python 目录,实际上更加推荐`uv`安装到虚拟环境。 ````bash pip install pydantic mcp requests --trusted-host mirrors.huaweicloud.com -i https://mirrors.huaweicloud.com/repository/pypi/simple @@ -25,11 +25,11 @@ wget https://gitee.com/openeuler/oeDeploy/blob/master/oedp-mcp/mcp-make-oedp-plu ## 2. MCP 配置 -当前示例使用 VScode 开发平台,用 Remote ssh 连接到一个 openEuler24.03sp1 的 linux 环境。 +当前示例使用 VScode 开发平台,用 Remote ssh 连接到一个 openEuler24.03sp1 的 linux 环境,并以家目录`~`为项目路径。 -在插件 Roo Code中配置了 DeepSeek-V3 的API。 +在插件 Roo Code 中配置了 DeepSeek-V3 的API。 -打开 MCP 配置页面,编辑 MCP 配置文件 `mcp_settings.json`,在 `mcpServers`中新增如下内容: +打开 MCP 配置页面,编辑 MCP 的项目配置文件`.roo/mcp.json`,修改如下: ````json { @@ -40,7 +40,7 @@ wget https://gitee.com/openeuler/oeDeploy/blob/master/oedp-mcp/mcp-make-oedp-plu "mcp-oedp": { "command": "python3", "args": [ - "/root/.oedp/mcp/mcp-oedp.py" + ".oedp/mcp/mcp-oedp.py" // 请根据实际情况调整路径 ], "disabled": false, "alwaysAllow": [] @@ -48,7 +48,7 @@ wget https://gitee.com/openeuler/oeDeploy/blob/master/oedp-mcp/mcp-make-oedp-plu "mcp-make-oedp-plugin": { "command": "python3", "args": [ - "/root/.oedp/mcp/mcp-make-oedp-plugin.py" + ".oedp/mcp/mcp-make-oedp-plugin.py" // 请根据实际情况调整路径 ], "disabled": false, "alwaysAllow": [] @@ -57,7 +57,7 @@ wget https://gitee.com/openeuler/oeDeploy/blob/master/oedp-mcp/mcp-make-oedp-plu } ```` -配置完成后,可以在 MCP 列表上看看到 `mcp-oedp`和 `mcp-make-oedp-plugin`,且状态正常。 +配置完成后,可以在 MCP 列表上看看到`mcp-oedp`和`mcp-make-oedp-plugin`,且状态正常。 > 如果出现报错,请根据提示信息检查 python 组件依赖是否满足。 diff --git a/oedp-mcp/mcp-make-oedp-plugin.py b/oedp-mcp/mcp-make-oedp-plugin.py index b504e7d..6a92595 100644 --- a/oedp-mcp/mcp-make-oedp-plugin.py +++ b/oedp-mcp/mcp-make-oedp-plugin.py @@ -1,6 +1,4 @@ from mcp.server.fastmcp import FastMCP -import requests -import subprocess import os DEFAULT_DIR = "~/.oedp/" @@ -28,13 +26,12 @@ async def make_plugin_auto(plugin: str, parent_dir: str) -> str: develop_guide_path = os.path.abspath(os.path.expanduser(DEVELOP_GUIDE_PATH)) - return f"""编写一个oeDeploy插件分为多个步骤: -1. (重要!)仔细阅读oeDeploy插件的开发文档{develop_guide_path} -2. 根据用户对eDeploy插件功能的详细描述,完成对oeDeploy插件的开发 -3. 开发完成后,用指定方式打包成tar.gz到{parent_dir}目录下(如果有同名文件则强制覆盖) -4. 再调用`oedp info -p {parent_dir}/{plugin}`进行测试 -5. 测试通过后,不用执行oedp部署操作 -""" + return "请帮我执行: {" + f""" +1. (重要!)仔细阅读oeDeploy插件的开发文档{develop_guide_path},根据用户对eDeploy插件功能的详细描述,完成对oeDeploy插件的开发 +2. 开发完成后,用指定方式打包成tar.gz到{parent_dir}目录下(如果有同名文件则强制覆盖) +3. 再调用`oedp info -p {parent_dir}/{plugin}`进行测试 +4. 测试通过后,不用执行oedp部署操作 +""" + "}" if __name__ == "__main__": # Initialize and run the server diff --git a/oedp-mcp/mcp-oedp.py b/oedp-mcp/mcp-oedp.py index 3010e23..fe6b856 100644 --- a/oedp-mcp/mcp-oedp.py +++ b/oedp-mcp/mcp-oedp.py @@ -8,7 +8,7 @@ DEFAULT_DIR = "~/.oedp/" # Initialize FastMCP server mcp = FastMCP("安装部署命令行工具oedp调用方法", log_level="ERROR") -def validate_project_structure(project: str) -> str: +def _validate_project_structure(project: str) -> str: """校验项目目录结构 Args: @@ -24,7 +24,7 @@ def validate_project_structure(project: str) -> str: return f"Missing required file/directory: {f}" return "" -def check_oedp_installed() -> str: +def _check_oedp_installed() -> str: """检查oedp是否安装 Returns: @@ -144,7 +144,7 @@ async def remove_oedp() -> str: @mcp.tool() async def oedp_init_plugin(plugin: str, parent_dir: str) -> str: - """获取已经存在的oeDeploy插件(又称oedp插件),并初始化到{parent_dir}目录 + """获取已经存在的oeDeploy插件(又称oedp插件),并初始化 Args: plugin: oeDeploy插件名称或.tar.gz文件路径/名称 @@ -217,7 +217,7 @@ async def oedp_init_plugin(plugin: str, parent_dir: str) -> str: except requests.exceptions.RequestException: # 所有获取方式都失败,检查现有目录 if os.path.exists(plugin_dir): - validation_result = validate_project_structure(plugin_dir) + validation_result = _validate_project_structure(plugin_dir) if not validation_result: return "[Success] (Using existing valid plugin directory)" return f"[Fail]Existing directory is invalid: {validation_result}" @@ -226,22 +226,100 @@ async def oedp_init_plugin(plugin: str, parent_dir: str) -> str: except Exception as e: return f"[Fail]Unexpected error: {str(e)}" +@mcp.tool() +async def oedp_info_plugin(project: str) -> str: + """查询oeDeploy插件(又称oedp插件)信息,仅在明确指定project路径时触发 + + Args: + project: oeDeploy插件的项目目录, 其中必定有config.yaml,main.yaml,workspace/ + """ + + # 校验项目目录结构 + abs_project = os.path.abspath(os.path.expanduser(project)) + validation_result = _validate_project_structure(abs_project) + if validation_result: + return f"[Fail]{validation_result}" + + # 检查oedp是否安装 + oedp_check_result = _check_oedp_installed() + if oedp_check_result: + return f"[Fail]{oedp_check_result}" + + # 执行安装命令 + try: + result = subprocess.run( + ["oedp", "info", "-p", abs_project], + capture_output=True, + text=True + ) + + log_text = result.stdout + "\n" + result.stderr + + if result.returncode == 0: + return "[Success]" + "\n" + log_text + else: + return f"[Fail]Installation failed" + "\n" + log_text + + except subprocess.CalledProcessError as e: + return f"[Fail]Command execution failed: {str(e)}" + except Exception as e: + return f"[Fail]Unexpected error: {str(e)}" + @mcp.tool() async def oedp_setup_plugin(operation: str, project: str) -> str: - """配置oeDeploy插件(又称oedp插件): 根据operation, 修改oeDeploy插件的配置文件{project}/config.yaml + """配置oeDeploy插件(又称oedp插件): 根据operation,修改oeDeploy插件的配置文件{project}/config.yaml Args: operation: 用户对oeDeploy插件config.yaml的修改说明(人类描述语言) - project: oeDeploy插件的项目目录, 其中必定有config.yaml,main.yaml,workspace/ + project: oeDeploy插件的项目目录,其中必定有config.yaml,main.yaml,workspace/ """ # 校验项目目录结构 abs_project = os.path.abspath(os.path.expanduser(project)) - validation_result = validate_project_structure(abs_project) + validation_result = _validate_project_structure(abs_project) if validation_result: return f"[Fail]{validation_result}" - return f"请根据用户的指令'{operation}', 修改{abs_project}/config.yaml" + return "请帮我执行: { " + f"修改{abs_project}/config.yaml.依据来自用户描述[{operation}]" + " }" + +@mcp.tool() +async def oedp_run_action_plugin(action: str, project: str) -> str: + """运行oeDeploy插件(又称oedp插件)的特定操作action,仅在明确指定project路径时触发 + + Args: + action: oeDeploy插件的一个操作名称 + project: oeDeploy插件的项目目录, 其中必定有config.yaml,main.yaml,workspace/ + """ + try: + # 校验项目目录结构 + abs_project = os.path.abspath(os.path.expanduser(project)) + validation_result = _validate_project_structure(abs_project) + if validation_result: + return f"[Fail]{validation_result}" + + # 检查oedp是否安装 + oedp_check_result = _check_oedp_installed() + if oedp_check_result: + return f"[Fail]{oedp_check_result}" + + # 执行命令 + result = subprocess.run( + ["oedp", "run", action, "-p", abs_project], + capture_output=True, + text=True + ) + + log_text = result.stdout + "\n" + result.stderr + + if result.returncode == 0: + return "[Success]" + "\n" + log_text + else: + return f"[Fail]Execution failed" + "\n" + log_text + + except subprocess.CalledProcessError as e: + return f"[Fail]Command execution failed: {str(e)}" + except Exception as e: + return f"[Fail]Unexpected error: {str(e)}" @mcp.tool() async def oedp_run_install_plugin(project: str) -> str: @@ -253,12 +331,12 @@ async def oedp_run_install_plugin(project: str) -> str: try: # 校验项目目录结构 abs_project = os.path.abspath(os.path.expanduser(project)) - validation_result = validate_project_structure(abs_project) + validation_result = _validate_project_structure(abs_project) if validation_result: return f"[Fail]{validation_result}" # 检查oedp是否安装 - oedp_check_result = check_oedp_installed() + oedp_check_result = _check_oedp_installed() if oedp_check_result: return f"[Fail]{oedp_check_result}" @@ -283,7 +361,7 @@ async def oedp_run_install_plugin(project: str) -> str: @mcp.tool() async def oedp_run_uninstall_plugin(project: str) -> str: - """运行oeDeploy插件(又称oedp插件)的卸载流程 + """运行oeDeploy插件(又称oedp插件)的卸载流程,仅在明确指定project路径时触发 Args: project: oeDeploy插件的项目目录, 其中必定有config.yaml,main.yaml,workspace/ @@ -291,12 +369,12 @@ async def oedp_run_uninstall_plugin(project: str) -> str: try: # 校验项目目录结构 abs_project = os.path.abspath(os.path.expanduser(project)) - validation_result = validate_project_structure(abs_project) + validation_result = _validate_project_structure(abs_project) if validation_result: return f"[Fail]{validation_result}" # 检查oedp是否安装 - oedp_check_result = check_oedp_installed() + oedp_check_result = _check_oedp_installed() if oedp_check_result: return f"[Fail]{oedp_check_result}" @@ -331,17 +409,17 @@ async def oedp_install_software_one_click(software: str, operation: str) -> str: """ # 检查oedp是否安装 - oedp_check_result = check_oedp_installed() + oedp_check_result = _check_oedp_installed() if oedp_check_result: return f"[Fail]{oedp_check_result}" parent_dir = os.path.abspath(os.path.expanduser(DEFAULT_DIR)) - return f"""用oeDeploy一键执行特定软件的部署流程(install)分为多个步骤: + return "请帮我执行: {" + f""" 1. 调用oedp_init_plugin方法,将指定的oeDeploy插件[{software}]初始化到{parent_dir}目录 2. 调用oedp_setup_plugin方法,根据用户的指令[{operation}],修改oeDeploy插件的配置文件{parent_dir}/{software}/config.yaml 3. 调用oedp_run_install_plugin方法,运行oeDeploy插件的安装部署流程 项目路径{parent_dir}/{software} -""" +""" + "}" if __name__ == "__main__": # Initialize and run the server -- Gitee