ssh-licco 2.1.2__tar.gz → 2.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ssh_licco-2.1.2/ssh_licco.egg-info → ssh_licco-2.1.4}/PKG-INFO +18 -2
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/README.md +17 -1
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/pyproject.toml +1 -1
- {ssh_licco-2.1.2 → ssh_licco-2.1.4/ssh_licco.egg-info}/PKG-INFO +18 -2
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/__init__.py +2 -2
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/file_transfer.py +99 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/LICENSE +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/setup.cfg +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/SOURCES.txt +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/dependency_links.txt +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/entry_points.txt +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/requires.txt +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/top_level.txt +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/__main__.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/approval.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/audit_logger.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/batch_executor.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/cli.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/__init__.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/additional_clients.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/factory.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/interface.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/paramiko_client.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/config_manager.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/connection_config.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/connection_pool.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/exceptions.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/executor.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/__init__.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/approval.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/connect.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/context.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/docker.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/execute.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/host.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/key.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/process.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/schemas.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/session.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/utils.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/key_manager.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/logging_config.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/runtime_guard.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/secret_provider.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/security.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/server.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/service.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/session_manager.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/tunnel.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/watchdog.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_config_manager.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_key_manager.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_security.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_server.py +0 -0
- {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_session_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssh-licco
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: SSH Model Context Protocol Server - Enable SSH functionality for AI models
|
|
5
5
|
Author-email: SSH LICCO Team <contact@ssh-licco.dev>
|
|
6
6
|
License: MIT
|
|
@@ -86,8 +86,24 @@ Dynamic: license-file
|
|
|
86
86
|
- 🐳 **Docker 支持** - Docker 构建和状态监控
|
|
87
87
|
- 📋 **后台任务** - 可靠的后台进程启动(nohup + bash -c 包装,单次 SSH 调用无竞态)
|
|
88
88
|
- 🖥️ **screen/tmux 会话** - 持久化远程会话,SSH 断开后进程依然存活
|
|
89
|
+
- 🪟 **Windows 服务器支持** - 支持 Windows Server(OpenSSH for Windows)与 Linux/macOS 目标主机
|
|
89
90
|
- 🔍 **进程管理** - 启动/停止/查询远程进程、SSH 端口转发(tunnel)
|
|
90
91
|
- 🔍 **看门狗** - 任务监控、心跳检测、全局异常处理
|
|
92
|
+
- 🛡️ **文件传输路径安全校验** - `ssh_file_transfer` delete 自动识别 Windows / Unix 路径风格并拦截敏感路径与路径遍历
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🖥️ 目标主机支持
|
|
97
|
+
|
|
98
|
+
SSH-LICCO 基于标准 SSH/SFTP 协议,可连接以下目标主机:
|
|
99
|
+
|
|
100
|
+
| 操作系统 | 要求 | 备注 |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| **Linux** | OpenSSH 7.0+ | 推荐,完整支持所有功能 |
|
|
103
|
+
| **Windows Server** | OpenSSH for Windows / PowerShell Remoting over SSH | v2.1.3+ 支持 Windows 路径风格与安全校验 |
|
|
104
|
+
| **macOS** | 系统内置 OpenSSH | 完整支持 |
|
|
105
|
+
|
|
106
|
+
> **提示**:连接 Windows 服务器时,请使用 Windows 风格路径(如 `C:\temp\file.txt`),系统会自动识别并进行路径安全校验。
|
|
91
107
|
|
|
92
108
|
---
|
|
93
109
|
|
|
@@ -241,7 +257,7 @@ SSH 跳板模式部署的生产必做加固,补齐跳板机单点风险:
|
|
|
241
257
|
| `ssh_connect` | 连接管理 | 自动读取环境变量/配置,支持密码+密钥认证,可保存配置,登录后自动执行命令 |
|
|
242
258
|
| `ssh_execute` | 命令执行 | 自动连接、智能后台检测、长任务等待、超时控制,支持 nohup/screen/tmux 三种后台模式;v2.1.0 新增 `approval_id`(高危审批)与 `remote_guard`(双层拦截)参数 |
|
|
243
259
|
| `ssh_disconnect` | 会话管理 | 断开指定会话 OR 列出所有活跃会话 |
|
|
244
|
-
| `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8
|
|
260
|
+
| `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作);v2.1.3+ delete 操作新增 Windows/Unix 敏感路径拦截与路径遍历防护 |
|
|
245
261
|
| `ssh_host` | 主机管理 | `action=list/add/remove` 增删查主机配置 |
|
|
246
262
|
| `ssh_docker` | Docker 管理 | `action=ps/images/build/logs` 全生命周期管理 |
|
|
247
263
|
| `ssh_generate_key` | 密钥生成 | RSA / Ed25519 密钥对 |
|
|
@@ -53,8 +53,24 @@
|
|
|
53
53
|
- 🐳 **Docker 支持** - Docker 构建和状态监控
|
|
54
54
|
- 📋 **后台任务** - 可靠的后台进程启动(nohup + bash -c 包装,单次 SSH 调用无竞态)
|
|
55
55
|
- 🖥️ **screen/tmux 会话** - 持久化远程会话,SSH 断开后进程依然存活
|
|
56
|
+
- 🪟 **Windows 服务器支持** - 支持 Windows Server(OpenSSH for Windows)与 Linux/macOS 目标主机
|
|
56
57
|
- 🔍 **进程管理** - 启动/停止/查询远程进程、SSH 端口转发(tunnel)
|
|
57
58
|
- 🔍 **看门狗** - 任务监控、心跳检测、全局异常处理
|
|
59
|
+
- 🛡️ **文件传输路径安全校验** - `ssh_file_transfer` delete 自动识别 Windows / Unix 路径风格并拦截敏感路径与路径遍历
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🖥️ 目标主机支持
|
|
64
|
+
|
|
65
|
+
SSH-LICCO 基于标准 SSH/SFTP 协议,可连接以下目标主机:
|
|
66
|
+
|
|
67
|
+
| 操作系统 | 要求 | 备注 |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| **Linux** | OpenSSH 7.0+ | 推荐,完整支持所有功能 |
|
|
70
|
+
| **Windows Server** | OpenSSH for Windows / PowerShell Remoting over SSH | v2.1.3+ 支持 Windows 路径风格与安全校验 |
|
|
71
|
+
| **macOS** | 系统内置 OpenSSH | 完整支持 |
|
|
72
|
+
|
|
73
|
+
> **提示**:连接 Windows 服务器时,请使用 Windows 风格路径(如 `C:\temp\file.txt`),系统会自动识别并进行路径安全校验。
|
|
58
74
|
|
|
59
75
|
---
|
|
60
76
|
|
|
@@ -208,7 +224,7 @@ SSH 跳板模式部署的生产必做加固,补齐跳板机单点风险:
|
|
|
208
224
|
| `ssh_connect` | 连接管理 | 自动读取环境变量/配置,支持密码+密钥认证,可保存配置,登录后自动执行命令 |
|
|
209
225
|
| `ssh_execute` | 命令执行 | 自动连接、智能后台检测、长任务等待、超时控制,支持 nohup/screen/tmux 三种后台模式;v2.1.0 新增 `approval_id`(高危审批)与 `remote_guard`(双层拦截)参数 |
|
|
210
226
|
| `ssh_disconnect` | 会话管理 | 断开指定会话 OR 列出所有活跃会话 |
|
|
211
|
-
| `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8
|
|
227
|
+
| `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作);v2.1.3+ delete 操作新增 Windows/Unix 敏感路径拦截与路径遍历防护 |
|
|
212
228
|
| `ssh_host` | 主机管理 | `action=list/add/remove` 增删查主机配置 |
|
|
213
229
|
| `ssh_docker` | Docker 管理 | `action=ps/images/build/logs` 全生命周期管理 |
|
|
214
230
|
| `ssh_generate_key` | 密钥生成 | RSA / Ed25519 密钥对 |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssh-licco
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: SSH Model Context Protocol Server - Enable SSH functionality for AI models
|
|
5
5
|
Author-email: SSH LICCO Team <contact@ssh-licco.dev>
|
|
6
6
|
License: MIT
|
|
@@ -86,8 +86,24 @@ Dynamic: license-file
|
|
|
86
86
|
- 🐳 **Docker 支持** - Docker 构建和状态监控
|
|
87
87
|
- 📋 **后台任务** - 可靠的后台进程启动(nohup + bash -c 包装,单次 SSH 调用无竞态)
|
|
88
88
|
- 🖥️ **screen/tmux 会话** - 持久化远程会话,SSH 断开后进程依然存活
|
|
89
|
+
- 🪟 **Windows 服务器支持** - 支持 Windows Server(OpenSSH for Windows)与 Linux/macOS 目标主机
|
|
89
90
|
- 🔍 **进程管理** - 启动/停止/查询远程进程、SSH 端口转发(tunnel)
|
|
90
91
|
- 🔍 **看门狗** - 任务监控、心跳检测、全局异常处理
|
|
92
|
+
- 🛡️ **文件传输路径安全校验** - `ssh_file_transfer` delete 自动识别 Windows / Unix 路径风格并拦截敏感路径与路径遍历
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🖥️ 目标主机支持
|
|
97
|
+
|
|
98
|
+
SSH-LICCO 基于标准 SSH/SFTP 协议,可连接以下目标主机:
|
|
99
|
+
|
|
100
|
+
| 操作系统 | 要求 | 备注 |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| **Linux** | OpenSSH 7.0+ | 推荐,完整支持所有功能 |
|
|
103
|
+
| **Windows Server** | OpenSSH for Windows / PowerShell Remoting over SSH | v2.1.3+ 支持 Windows 路径风格与安全校验 |
|
|
104
|
+
| **macOS** | 系统内置 OpenSSH | 完整支持 |
|
|
105
|
+
|
|
106
|
+
> **提示**:连接 Windows 服务器时,请使用 Windows 风格路径(如 `C:\temp\file.txt`),系统会自动识别并进行路径安全校验。
|
|
91
107
|
|
|
92
108
|
---
|
|
93
109
|
|
|
@@ -241,7 +257,7 @@ SSH 跳板模式部署的生产必做加固,补齐跳板机单点风险:
|
|
|
241
257
|
| `ssh_connect` | 连接管理 | 自动读取环境变量/配置,支持密码+密钥认证,可保存配置,登录后自动执行命令 |
|
|
242
258
|
| `ssh_execute` | 命令执行 | 自动连接、智能后台检测、长任务等待、超时控制,支持 nohup/screen/tmux 三种后台模式;v2.1.0 新增 `approval_id`(高危审批)与 `remote_guard`(双层拦截)参数 |
|
|
243
259
|
| `ssh_disconnect` | 会话管理 | 断开指定会话 OR 列出所有活跃会话 |
|
|
244
|
-
| `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8
|
|
260
|
+
| `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作);v2.1.3+ delete 操作新增 Windows/Unix 敏感路径拦截与路径遍历防护 |
|
|
245
261
|
| `ssh_host` | 主机管理 | `action=list/add/remove` 增删查主机配置 |
|
|
246
262
|
| `ssh_docker` | Docker 管理 | `action=ps/images/build/logs` 全生命周期管理 |
|
|
247
263
|
| `ssh_generate_key` | 密钥生成 | RSA / Ed25519 密钥对 |
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
import shlex
|
|
7
|
+
from pathlib import PurePosixPath, PureWindowsPath
|
|
7
8
|
|
|
8
9
|
from mcp.types import TextContent
|
|
9
10
|
|
|
@@ -12,6 +13,101 @@ from .context import HandlerContext
|
|
|
12
13
|
from .utils import ensure_session
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
# 远程 Unix/Linux 敏感路径黑名单
|
|
17
|
+
FORBIDDEN_REMOTE_PATHS = [
|
|
18
|
+
"/etc",
|
|
19
|
+
"/root",
|
|
20
|
+
"/boot",
|
|
21
|
+
"/proc",
|
|
22
|
+
"/sys",
|
|
23
|
+
"/dev",
|
|
24
|
+
"/bin",
|
|
25
|
+
"/sbin",
|
|
26
|
+
"/usr/bin",
|
|
27
|
+
"/usr/sbin",
|
|
28
|
+
"/lib",
|
|
29
|
+
"/lib64",
|
|
30
|
+
"/var/lib/postgresql",
|
|
31
|
+
"/var/lib/mysql",
|
|
32
|
+
"/var/lib/redis",
|
|
33
|
+
"/var/lib/docker",
|
|
34
|
+
"/var/log",
|
|
35
|
+
"/var/spool",
|
|
36
|
+
"/var/mail",
|
|
37
|
+
"/home/*/.ssh",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
# 远程 Windows 敏感路径黑名单(支持大小写不敏感匹配)
|
|
41
|
+
FORBIDDEN_WINDOWS_PATHS = [
|
|
42
|
+
r"C:\Windows",
|
|
43
|
+
r"C:\Windows\System32",
|
|
44
|
+
r"C:\Windows\SysWOW64",
|
|
45
|
+
r"C:\Program Files",
|
|
46
|
+
r"C:\Program Files (x86)",
|
|
47
|
+
r"C:\ProgramData",
|
|
48
|
+
r"C:\inetpub",
|
|
49
|
+
r"C:\Users\Default",
|
|
50
|
+
r"C:\Users\Public",
|
|
51
|
+
r"C:\Recovery",
|
|
52
|
+
r"C:\System Volume Information",
|
|
53
|
+
r"C:\$Recycle.Bin",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _is_windows_path(path: str) -> bool:
|
|
58
|
+
"""根据路径特征判断是否为 Windows 风格路径。"""
|
|
59
|
+
if re.match(r"^[A-Za-z]:\\", path):
|
|
60
|
+
return True
|
|
61
|
+
if path.startswith("\\\\"):
|
|
62
|
+
return True
|
|
63
|
+
# 仅包含反斜杠且不含正斜杠时,视为 Windows 路径
|
|
64
|
+
if "\\" in path and "/" not in path:
|
|
65
|
+
return True
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _validate_remote_path(remote_path: str, operation: str = "access") -> tuple[bool, str]:
|
|
70
|
+
"""校验远程路径是否安全,自动识别 Windows / Unix 路径风格。
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
(is_safe, error_message)
|
|
74
|
+
"""
|
|
75
|
+
if not remote_path or not remote_path.strip():
|
|
76
|
+
return False, "远程路径不能为空"
|
|
77
|
+
|
|
78
|
+
remote_path = remote_path.strip()
|
|
79
|
+
|
|
80
|
+
if _is_windows_path(remote_path):
|
|
81
|
+
# Windows 路径处理
|
|
82
|
+
normalized = str(PureWindowsPath(remote_path))
|
|
83
|
+
if ".." in normalized.split("\\"):
|
|
84
|
+
return False, f"Windows 路径遍历被阻止:{remote_path}"
|
|
85
|
+
|
|
86
|
+
upper_normalized = normalized.upper()
|
|
87
|
+
for forbidden in FORBIDDEN_WINDOWS_PATHS:
|
|
88
|
+
upper_forbidden = forbidden.upper().rstrip("\\")
|
|
89
|
+
if upper_normalized == upper_forbidden or upper_normalized.startswith(upper_forbidden + "\\"):
|
|
90
|
+
return False, f"禁止{operation} Windows 敏感路径:{forbidden}"
|
|
91
|
+
|
|
92
|
+
return True, ""
|
|
93
|
+
|
|
94
|
+
# Unix/Linux 路径处理
|
|
95
|
+
normalized = str(PurePosixPath(remote_path)).rstrip("/") or "/"
|
|
96
|
+
if ".." in normalized.split("/"):
|
|
97
|
+
return False, f"路径遍历被阻止:{remote_path}"
|
|
98
|
+
|
|
99
|
+
path_for_check = normalized.rstrip("/*") or "/"
|
|
100
|
+
for forbidden in FORBIDDEN_REMOTE_PATHS:
|
|
101
|
+
if forbidden.endswith("/*"):
|
|
102
|
+
prefix = forbidden[:-1]
|
|
103
|
+
if path_for_check.startswith(prefix) or path_for_check + "/" == prefix:
|
|
104
|
+
return False, f"禁止{operation}敏感路径:{forbidden}"
|
|
105
|
+
elif path_for_check == forbidden or path_for_check.startswith(forbidden + "/"):
|
|
106
|
+
return False, f"禁止{operation}敏感路径:{forbidden}"
|
|
107
|
+
|
|
108
|
+
return True, ""
|
|
109
|
+
|
|
110
|
+
|
|
15
111
|
async def handle_file_transfer(ctx: HandlerContext, args: dict) -> list[TextContent]:
|
|
16
112
|
"""Transfer files between local and remote, or perform remote file operations."""
|
|
17
113
|
session_id = await ensure_session(ctx, args, handle_connect)
|
|
@@ -51,6 +147,9 @@ async def handle_file_transfer(ctx: HandlerContext, args: dict) -> list[TextCont
|
|
|
51
147
|
elif direction == "delete":
|
|
52
148
|
if not remote_path:
|
|
53
149
|
return [TextContent(type="text", text="delete requires remote_path")]
|
|
150
|
+
safe, err = _validate_remote_path(remote_path, operation="delete")
|
|
151
|
+
if not safe:
|
|
152
|
+
return [TextContent(type="text", text=f"❌ Delete blocked: {err}")]
|
|
54
153
|
result = await session.delete_file(remote_path)
|
|
55
154
|
elif direction == "mkdir":
|
|
56
155
|
if not remote_path:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|