ssh-licco 2.7.2__tar.gz → 2.7.3__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.7.2/ssh_licco.egg-info → ssh_licco-2.7.3}/PKG-INFO +2 -1
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/README.md +1 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/pyproject.toml +1 -1
- {ssh_licco-2.7.2 → ssh_licco-2.7.3/ssh_licco.egg-info}/PKG-INFO +2 -1
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_licco.egg-info/SOURCES.txt +0 -1
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/__init__.py +2 -2
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/server.py +44 -16
- ssh_licco-2.7.2/ssh_mcp/cli.py +0 -135
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/LICENSE +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/setup.cfg +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_licco.egg-info/dependency_links.txt +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_licco.egg-info/entry_points.txt +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_licco.egg-info/requires.txt +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_licco.egg-info/top_level.txt +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/__main__.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/audit_logger.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/batch_executor.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/clients/__init__.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/clients/additional_clients.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/clients/factory.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/clients/interface.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/clients/paramiko_client.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/config_manager.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/connection_config.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/connection_pool.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/exceptions.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/executor.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/__init__.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/connect.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/context.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/docker.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/execute.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/file_transfer.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/host.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/key.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/process.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/schemas.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/session.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/handlers/utils.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/key_manager.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/logging_config.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/security.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/service.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/session_manager.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/tunnel.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/ssh_mcp/watchdog.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/tests/test_config_manager.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/tests/test_key_manager.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/tests/test_security.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/tests/test_server.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/tests/test_session_manager.py +0 -0
- {ssh_licco-2.7.2 → ssh_licco-2.7.3}/tests/test_watchdog.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssh-licco
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.3
|
|
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
|
|
@@ -47,6 +47,7 @@ Dynamic: license-file
|
|
|
47
47
|
## 📚 文档导航
|
|
48
48
|
|
|
49
49
|
### 快速开始
|
|
50
|
+
- **[🐣 新手指南](docs/BEGINNER_GUIDE.md)** - 零基础上手(推荐从这开始)
|
|
50
51
|
- **[⬇️ 安装指南](#-快速安装)** - 2 种安装方式
|
|
51
52
|
- **[🚀 快速开始](#-快速开始)** - 5 分钟上手
|
|
52
53
|
- **[📋 配置模板](#-完整配置示例)** - 开箱即用的配置
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssh-licco
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.3
|
|
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
|
|
@@ -47,6 +47,7 @@ Dynamic: license-file
|
|
|
47
47
|
## 📚 文档导航
|
|
48
48
|
|
|
49
49
|
### 快速开始
|
|
50
|
+
- **[🐣 新手指南](docs/BEGINNER_GUIDE.md)** - 零基础上手(推荐从这开始)
|
|
50
51
|
- **[⬇️ 安装指南](#-快速安装)** - 2 种安装方式
|
|
51
52
|
- **[🚀 快速开始](#-快速开始)** - 5 分钟上手
|
|
52
53
|
- **[📋 配置模板](#-完整配置示例)** - 开箱即用的配置
|
|
@@ -11,7 +11,14 @@ from typing import Any
|
|
|
11
11
|
|
|
12
12
|
from mcp.server import Server
|
|
13
13
|
from mcp.server.stdio import stdio_server
|
|
14
|
-
from mcp.types import
|
|
14
|
+
from mcp.types import (
|
|
15
|
+
CallToolRequestParams,
|
|
16
|
+
CallToolResult,
|
|
17
|
+
ListToolsResult,
|
|
18
|
+
PaginatedRequestParams,
|
|
19
|
+
TextContent,
|
|
20
|
+
Tool,
|
|
21
|
+
)
|
|
15
22
|
|
|
16
23
|
from .audit_logger import get_audit_logger
|
|
17
24
|
from .config_manager import ConfigManager, SSHConfig, SSHHost
|
|
@@ -212,24 +219,45 @@ class SSHMCPServer:
|
|
|
212
219
|
return True, ""
|
|
213
220
|
|
|
214
221
|
def _setup_handlers(self):
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
222
|
+
self.server.add_request_handler(
|
|
223
|
+
"tools/list", PaginatedRequestParams, self._handle_list_tools
|
|
224
|
+
)
|
|
225
|
+
self.server.add_request_handler(
|
|
226
|
+
"tools/call", CallToolRequestParams, self._handle_call_tool
|
|
227
|
+
)
|
|
218
228
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
async def _handle_list_tools(
|
|
230
|
+
self, ctx: Any, params: PaginatedRequestParams
|
|
231
|
+
) -> ListToolsResult:
|
|
232
|
+
return ListToolsResult(tools=list(schemas.TOOLS.values()))
|
|
233
|
+
|
|
234
|
+
async def _handle_call_tool(
|
|
235
|
+
self, ctx: Any, params: CallToolRequestParams
|
|
236
|
+
) -> CallToolResult:
|
|
237
|
+
allowed, msg = self._check_rate_limit()
|
|
238
|
+
if not allowed:
|
|
239
|
+
return CallToolResult(
|
|
240
|
+
content=[TextContent(type="text", text=msg)], is_error=False
|
|
241
|
+
)
|
|
224
242
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
243
|
+
handler = HANDLERS.get(params.name)
|
|
244
|
+
if handler is None:
|
|
245
|
+
return CallToolResult(
|
|
246
|
+
content=[
|
|
247
|
+
TextContent(type="text", text=f"Unknown tool: {params.name}")
|
|
248
|
+
],
|
|
249
|
+
is_error=True,
|
|
250
|
+
)
|
|
228
251
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
252
|
+
try:
|
|
253
|
+
result = await handler(self._ctx, params.arguments or {})
|
|
254
|
+
content = result if isinstance(result, list) else [result]
|
|
255
|
+
return CallToolResult(content=content, is_error=False)
|
|
256
|
+
except Exception as e:
|
|
257
|
+
return CallToolResult(
|
|
258
|
+
content=[TextContent(type="text", text=f"Error: {str(e)}")],
|
|
259
|
+
is_error=True,
|
|
260
|
+
)
|
|
233
261
|
|
|
234
262
|
async def _handle_connect(self, args: dict) -> list[TextContent]:
|
|
235
263
|
"""合并 ssh_config + ssh_login + ssh_connect"""
|
ssh_licco-2.7.2/ssh_mcp/cli.py
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"""SSH-LICCO command line interface."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
import os
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
from ssh_mcp import __version__
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def _build_parser() -> argparse.ArgumentParser:
|
|
13
|
-
"""Build the CLI argument parser."""
|
|
14
|
-
parser = argparse.ArgumentParser(
|
|
15
|
-
prog="ssh-licco",
|
|
16
|
-
description="SSH-LICCO: Remote server management via MCP and CLI.",
|
|
17
|
-
)
|
|
18
|
-
parser.add_argument(
|
|
19
|
-
"--version",
|
|
20
|
-
action="version",
|
|
21
|
-
version=f"ssh-licco {__version__}",
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
subparsers = parser.add_subparsers(dest="subcommand", required=False)
|
|
25
|
-
|
|
26
|
-
# exec
|
|
27
|
-
exec_parser = subparsers.add_parser("exec", help="Execute a remote command")
|
|
28
|
-
exec_parser.add_argument("cmd", help="Command to execute")
|
|
29
|
-
exec_parser.add_argument("--host", default=None, help="Remote host")
|
|
30
|
-
exec_parser.add_argument("-u", "--username", default=None, help="SSH username")
|
|
31
|
-
exec_parser.add_argument("--password", default=None, help="SSH password")
|
|
32
|
-
exec_parser.add_argument(
|
|
33
|
-
"--connect-timeout", type=int, default=None, help="Connection timeout in seconds"
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
# upload
|
|
37
|
-
upload_parser = subparsers.add_parser("upload", help="Upload a file")
|
|
38
|
-
upload_parser.add_argument("local", help="Local file path")
|
|
39
|
-
upload_parser.add_argument("remote", help="Remote file path")
|
|
40
|
-
upload_parser.add_argument("--host", default=None, help="Remote host")
|
|
41
|
-
upload_parser.add_argument("-u", "--username", default=None, help="SSH username")
|
|
42
|
-
upload_parser.add_argument("--password", default=None, help="SSH password")
|
|
43
|
-
|
|
44
|
-
# download
|
|
45
|
-
download_parser = subparsers.add_parser("download", help="Download a file")
|
|
46
|
-
download_parser.add_argument("remote", help="Remote file path")
|
|
47
|
-
download_parser.add_argument("local", help="Local file path")
|
|
48
|
-
download_parser.add_argument("--host", default=None, help="Remote host")
|
|
49
|
-
download_parser.add_argument("-u", "--username", default=None, help="SSH username")
|
|
50
|
-
download_parser.add_argument("--password", default=None, help="SSH password")
|
|
51
|
-
|
|
52
|
-
# docker-build
|
|
53
|
-
docker_build_parser = subparsers.add_parser("docker-build", help="Build a Docker image")
|
|
54
|
-
docker_build_parser.add_argument("image", help="Image tag")
|
|
55
|
-
docker_build_parser.add_argument("-c", "--context", default=".", help="Build context")
|
|
56
|
-
docker_build_parser.add_argument("-f", "--dockerfile", default="Dockerfile", help="Dockerfile path")
|
|
57
|
-
docker_build_parser.add_argument("-t", "--timeout", type=int, default=600, help="Build timeout")
|
|
58
|
-
|
|
59
|
-
# serve
|
|
60
|
-
subparsers.add_parser("serve", help="Start the MCP server")
|
|
61
|
-
|
|
62
|
-
# list-hosts
|
|
63
|
-
subparsers.add_parser("list-hosts", help="List configured hosts")
|
|
64
|
-
|
|
65
|
-
return parser
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def _load_connection_config(args: argparse.Namespace) -> dict:
|
|
69
|
-
"""Load connection config from CLI args or environment variables."""
|
|
70
|
-
host = args.host or os.getenv("SSH_HOST")
|
|
71
|
-
username = args.username or os.getenv("SSH_USER")
|
|
72
|
-
password = args.password or os.getenv("SSH_PASSWORD")
|
|
73
|
-
port = args.port if getattr(args, "port", None) else 22
|
|
74
|
-
timeout = args.connect_timeout if getattr(args, "connect_timeout", None) else 30
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
"host": host,
|
|
78
|
-
"port": port,
|
|
79
|
-
"username": username,
|
|
80
|
-
"password": password,
|
|
81
|
-
"timeout": timeout,
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def main(argv: list[str] | None = None) -> int:
|
|
86
|
-
"""CLI entry point."""
|
|
87
|
-
parser = _build_parser()
|
|
88
|
-
args = parser.parse_args(argv)
|
|
89
|
-
|
|
90
|
-
if args.subcommand is None:
|
|
91
|
-
parser.print_help()
|
|
92
|
-
return 0
|
|
93
|
-
|
|
94
|
-
if args.subcommand == "serve":
|
|
95
|
-
from ssh_mcp.server import run_server
|
|
96
|
-
|
|
97
|
-
run_server()
|
|
98
|
-
return 0
|
|
99
|
-
|
|
100
|
-
if args.subcommand == "list-hosts":
|
|
101
|
-
from ssh_mcp.config_manager import ConfigManager
|
|
102
|
-
|
|
103
|
-
manager = ConfigManager()
|
|
104
|
-
hosts = manager.list_hosts()
|
|
105
|
-
if not hosts:
|
|
106
|
-
print("No hosts configured.")
|
|
107
|
-
return 0
|
|
108
|
-
for name, config in hosts.items():
|
|
109
|
-
print(f"{name}: {config.host}:{config.port} ({config.username})")
|
|
110
|
-
return 0
|
|
111
|
-
|
|
112
|
-
if args.subcommand == "exec":
|
|
113
|
-
config = _load_connection_config(args)
|
|
114
|
-
print(f"Would execute on {config['host']}: {args.cmd}")
|
|
115
|
-
return 0
|
|
116
|
-
|
|
117
|
-
if args.subcommand == "upload":
|
|
118
|
-
config = _load_connection_config(args)
|
|
119
|
-
print(f"Would upload {args.local} -> {config['host']}:{args.remote}")
|
|
120
|
-
return 0
|
|
121
|
-
|
|
122
|
-
if args.subcommand == "download":
|
|
123
|
-
config = _load_connection_config(args)
|
|
124
|
-
print(f"Would download {config['host']}:{args.remote} -> {args.local}")
|
|
125
|
-
return 0
|
|
126
|
-
|
|
127
|
-
if args.subcommand == "docker-build":
|
|
128
|
-
print(f"Would build Docker image {args.image} from {args.context}/{args.dockerfile}")
|
|
129
|
-
return 0
|
|
130
|
-
|
|
131
|
-
return 0
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if __name__ == "__main__":
|
|
135
|
-
sys.exit(main())
|
|
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
|