ssh-mcp-vn 0.1.0__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_mcp_vn-0.1.0/PKG-INFO +82 -0
- ssh_mcp_vn-0.1.0/README.md +62 -0
- ssh_mcp_vn-0.1.0/pyproject.toml +33 -0
- ssh_mcp_vn-0.1.0/setup.cfg +4 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_server.py +177 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_vn.egg-info/PKG-INFO +82 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_vn.egg-info/SOURCES.txt +9 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_vn.egg-info/dependency_links.txt +1 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_vn.egg-info/entry_points.txt +2 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_vn.egg-info/requires.txt +12 -0
- ssh_mcp_vn-0.1.0/src/ssh_mcp_vn.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ssh-mcp-vn
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: High-performance SSH & SFTP MCP Server for Linux
|
|
5
|
+
Author-email: NamHT <namht@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: mcp>=1.2.0
|
|
10
|
+
Requires-Dist: asyncssh>=2.14.0
|
|
11
|
+
Requires-Dist: pydantic>=2.8.0
|
|
12
|
+
Requires-Dist: pydantic-settings>=2.4.0
|
|
13
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
17
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
18
|
+
Requires-Dist: ruff>=0.5.0; extra == "dev"
|
|
19
|
+
Requires-Dist: mypy>=1.10.0; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# SSH & SFTP MCP Server (ssh-mcp-vn)
|
|
22
|
+
|
|
23
|
+
Một MCP (Model Context Protocol) Server mạnh mẽ dùng để thực thi lệnh (SSH) và truyền tải file (SFTP) trên **nhiều máy chủ Linux từ xa (multi-host)** cùng lúc.
|
|
24
|
+
|
|
25
|
+
## Hướng dẫn cài đặt
|
|
26
|
+
|
|
27
|
+
### Chạy qua UVX (Được khuyến nghị)
|
|
28
|
+
Bạn có thể chạy trực tiếp server này qua `uvx` mà không cần phải tải hay cài đặt thủ công:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uvx ssh-mcp-vn
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Các tính năng chính
|
|
35
|
+
|
|
36
|
+
- **Hỗ trợ Multi-host**: Có thể tương tác với nhiều máy chủ Linux mà không cần chạy nhiều instance.
|
|
37
|
+
- **Thực thi qua SSH**: Chạy lệnh bash/shell tùy ý trên máy chủ từ xa.
|
|
38
|
+
- **Quản lý thư mục**: Dễ dàng tạo cấu trúc thư mục từ xa (hoạt động giống lệnh `mkdir -p`).
|
|
39
|
+
- **Tải lên qua SFTP**: Đẩy file từ máy tính cá nhân lên máy chủ từ xa.
|
|
40
|
+
- **Tải về qua SFTP**: Tải file từ máy chủ từ xa về máy tính.
|
|
41
|
+
- **Liệt kê file bằng SFTP**: Xem danh sách các file trong một thư mục bất kỳ trên máy chủ.
|
|
42
|
+
|
|
43
|
+
## Cấu hình
|
|
44
|
+
|
|
45
|
+
MCP server này hỗ trợ nhận cấu hình dạng một chuỗi JSON (JSON string) qua biến môi trường `SSH_SERVERS`. Trong file `mcp_config.json`, bạn cấu hình theo định dạng như sau:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"ssh-server": {
|
|
51
|
+
"command": "uvx",
|
|
52
|
+
"args": [
|
|
53
|
+
"ssh-mcp-vn"
|
|
54
|
+
],
|
|
55
|
+
"env": {
|
|
56
|
+
"SSH_SERVERS": "[{\"host\":\"192.168.1.100\", \"user\":\"root\", \"password\":\"mat_khau_1\", \"port\":22}, {\"host\":\"192.168.1.101\", \"user\":\"ubuntu\", \"key_path\":\"/path/to/key.pem\"}]"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Các trường trong mảng JSON cấu hình
|
|
64
|
+
Trong mảng JSON cấu hình (`SSH_SERVERS`), mỗi object hỗ trợ các trường sau:
|
|
65
|
+
- `host` (bắt buộc): Địa chỉ IP hoặc Hostname của máy chủ SSH.
|
|
66
|
+
- `user` (bắt buộc): Tên đăng nhập (username).
|
|
67
|
+
- `port` (tùy chọn): Cổng SSH, mặc định là 22.
|
|
68
|
+
- `password` (tùy chọn): Mật khẩu đăng nhập.
|
|
69
|
+
- `key_path` (tùy chọn): Đường dẫn tuyệt đối đến file khóa bí mật (private key) nếu dùng key để đăng nhập.
|
|
70
|
+
|
|
71
|
+
## Danh sách công cụ (Tools)
|
|
72
|
+
|
|
73
|
+
*(Tất cả các công cụ đều yêu cầu tham số `host` để hệ thống biết sẽ thao tác trên máy chủ nào).*
|
|
74
|
+
|
|
75
|
+
- `ssh_execute_command`: Chạy một lệnh shell trên máy Linux từ xa.
|
|
76
|
+
- `ssh_create_folder`: Tạo thư mục từ xa.
|
|
77
|
+
- `sftp_upload_file`: Chuyển một file từ local lên máy chủ.
|
|
78
|
+
- `sftp_download_file`: Lấy một file từ máy chủ về local.
|
|
79
|
+
- `sftp_list_directory`: Liệt kê tất cả file trong một thư mục từ xa.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# SSH & SFTP MCP Server (ssh-mcp-vn)
|
|
2
|
+
|
|
3
|
+
Một MCP (Model Context Protocol) Server mạnh mẽ dùng để thực thi lệnh (SSH) và truyền tải file (SFTP) trên **nhiều máy chủ Linux từ xa (multi-host)** cùng lúc.
|
|
4
|
+
|
|
5
|
+
## Hướng dẫn cài đặt
|
|
6
|
+
|
|
7
|
+
### Chạy qua UVX (Được khuyến nghị)
|
|
8
|
+
Bạn có thể chạy trực tiếp server này qua `uvx` mà không cần phải tải hay cài đặt thủ công:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
uvx ssh-mcp-vn
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Các tính năng chính
|
|
15
|
+
|
|
16
|
+
- **Hỗ trợ Multi-host**: Có thể tương tác với nhiều máy chủ Linux mà không cần chạy nhiều instance.
|
|
17
|
+
- **Thực thi qua SSH**: Chạy lệnh bash/shell tùy ý trên máy chủ từ xa.
|
|
18
|
+
- **Quản lý thư mục**: Dễ dàng tạo cấu trúc thư mục từ xa (hoạt động giống lệnh `mkdir -p`).
|
|
19
|
+
- **Tải lên qua SFTP**: Đẩy file từ máy tính cá nhân lên máy chủ từ xa.
|
|
20
|
+
- **Tải về qua SFTP**: Tải file từ máy chủ từ xa về máy tính.
|
|
21
|
+
- **Liệt kê file bằng SFTP**: Xem danh sách các file trong một thư mục bất kỳ trên máy chủ.
|
|
22
|
+
|
|
23
|
+
## Cấu hình
|
|
24
|
+
|
|
25
|
+
MCP server này hỗ trợ nhận cấu hình dạng một chuỗi JSON (JSON string) qua biến môi trường `SSH_SERVERS`. Trong file `mcp_config.json`, bạn cấu hình theo định dạng như sau:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"ssh-server": {
|
|
31
|
+
"command": "uvx",
|
|
32
|
+
"args": [
|
|
33
|
+
"ssh-mcp-vn"
|
|
34
|
+
],
|
|
35
|
+
"env": {
|
|
36
|
+
"SSH_SERVERS": "[{\"host\":\"192.168.1.100\", \"user\":\"root\", \"password\":\"mat_khau_1\", \"port\":22}, {\"host\":\"192.168.1.101\", \"user\":\"ubuntu\", \"key_path\":\"/path/to/key.pem\"}]"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Các trường trong mảng JSON cấu hình
|
|
44
|
+
Trong mảng JSON cấu hình (`SSH_SERVERS`), mỗi object hỗ trợ các trường sau:
|
|
45
|
+
- `host` (bắt buộc): Địa chỉ IP hoặc Hostname của máy chủ SSH.
|
|
46
|
+
- `user` (bắt buộc): Tên đăng nhập (username).
|
|
47
|
+
- `port` (tùy chọn): Cổng SSH, mặc định là 22.
|
|
48
|
+
- `password` (tùy chọn): Mật khẩu đăng nhập.
|
|
49
|
+
- `key_path` (tùy chọn): Đường dẫn tuyệt đối đến file khóa bí mật (private key) nếu dùng key để đăng nhập.
|
|
50
|
+
|
|
51
|
+
## Danh sách công cụ (Tools)
|
|
52
|
+
|
|
53
|
+
*(Tất cả các công cụ đều yêu cầu tham số `host` để hệ thống biết sẽ thao tác trên máy chủ nào).*
|
|
54
|
+
|
|
55
|
+
- `ssh_execute_command`: Chạy một lệnh shell trên máy Linux từ xa.
|
|
56
|
+
- `ssh_create_folder`: Tạo thư mục từ xa.
|
|
57
|
+
- `sftp_upload_file`: Chuyển một file từ local lên máy chủ.
|
|
58
|
+
- `sftp_download_file`: Lấy một file từ máy chủ về local.
|
|
59
|
+
- `sftp_list_directory`: Liệt kê tất cả file trong một thư mục từ xa.
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
MIT
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ssh-mcp-vn"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "High-performance SSH & SFTP MCP Server for Linux"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "NamHT", email = "namht@example.com" }
|
|
12
|
+
]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
requires-python = ">=3.12"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"mcp>=1.2.0",
|
|
17
|
+
"asyncssh>=2.14.0",
|
|
18
|
+
"pydantic>=2.8.0",
|
|
19
|
+
"pydantic-settings>=2.4.0",
|
|
20
|
+
"python-dotenv>=1.0.0"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
ssh-mcp-vn = "ssh_mcp_server:main"
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"pytest>=8.0.0",
|
|
29
|
+
"pytest-asyncio>=0.23.0",
|
|
30
|
+
"pytest-cov>=4.1.0",
|
|
31
|
+
"ruff>=0.5.0",
|
|
32
|
+
"mypy>=1.10.0"
|
|
33
|
+
]
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
import argparse
|
|
5
|
+
import asyncssh
|
|
6
|
+
from typing import Optional, List, Dict, Any
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
class ServerConfig(BaseModel):
|
|
12
|
+
host: str
|
|
13
|
+
user: str
|
|
14
|
+
port: int = 22
|
|
15
|
+
password: Optional[str] = None
|
|
16
|
+
key_path: Optional[str] = None
|
|
17
|
+
|
|
18
|
+
class SshSettings(BaseSettings):
|
|
19
|
+
servers: str = "[]" # JSON string array of server configs
|
|
20
|
+
|
|
21
|
+
model_config = SettingsConfigDict(
|
|
22
|
+
env_prefix="SSH_",
|
|
23
|
+
env_file=".env",
|
|
24
|
+
env_file_encoding="utf-8",
|
|
25
|
+
extra="ignore"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
mcp = FastMCP("ssh-mcp-vn", description="SSH and SFTP Server (Multi-host)")
|
|
29
|
+
|
|
30
|
+
_parsed_servers: Dict[str, ServerConfig] = {}
|
|
31
|
+
|
|
32
|
+
def get_parsed_servers() -> Dict[str, ServerConfig]:
|
|
33
|
+
global _parsed_servers
|
|
34
|
+
if not _parsed_servers:
|
|
35
|
+
settings = SshSettings()
|
|
36
|
+
try:
|
|
37
|
+
servers_list = json.loads(settings.servers)
|
|
38
|
+
for s in servers_list:
|
|
39
|
+
config = ServerConfig(**s)
|
|
40
|
+
_parsed_servers[config.host] = config
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(f"Error parsing SSH_SERVERS JSON: {e}", file=sys.stderr)
|
|
43
|
+
return _parsed_servers
|
|
44
|
+
|
|
45
|
+
def get_server_config(host: str) -> ServerConfig:
|
|
46
|
+
servers = get_parsed_servers()
|
|
47
|
+
if host not in servers:
|
|
48
|
+
raise ValueError(f"Server configuration for host '{host}' not found.")
|
|
49
|
+
return servers[host]
|
|
50
|
+
|
|
51
|
+
async def create_connection(host: str) -> asyncssh.SSHClientConnection:
|
|
52
|
+
config = get_server_config(host)
|
|
53
|
+
|
|
54
|
+
connect_kwargs: Dict[str, Any] = {
|
|
55
|
+
"host": config.host,
|
|
56
|
+
"port": config.port,
|
|
57
|
+
"username": config.user,
|
|
58
|
+
"known_hosts": None # Accept any host key for simplicity in automated environments
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if config.password:
|
|
62
|
+
connect_kwargs["password"] = config.password
|
|
63
|
+
if config.key_path:
|
|
64
|
+
connect_kwargs["client_keys"] = [config.key_path]
|
|
65
|
+
|
|
66
|
+
return await asyncssh.connect(**connect_kwargs)
|
|
67
|
+
|
|
68
|
+
@mcp.tool()
|
|
69
|
+
async def ssh_execute_command(host: str, command: str) -> str:
|
|
70
|
+
"""Execute an arbitrary shell command on the remote Linux machine via SSH.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
host: The target SSH host IP or domain (must be configured in SSH_SERVERS).
|
|
74
|
+
command: The shell command to execute.
|
|
75
|
+
"""
|
|
76
|
+
try:
|
|
77
|
+
async with await create_connection(host) as conn:
|
|
78
|
+
result = await conn.run(command, check=False)
|
|
79
|
+
output = f"Exit Status: {result.exit_status}\n"
|
|
80
|
+
if result.stdout:
|
|
81
|
+
output += f"STDOUT:\n{result.stdout}\n"
|
|
82
|
+
if result.stderr:
|
|
83
|
+
output += f"STDERR:\n{result.stderr}\n"
|
|
84
|
+
return output
|
|
85
|
+
except Exception as e:
|
|
86
|
+
return f"Error executing command on {host}: {str(e)}"
|
|
87
|
+
|
|
88
|
+
@mcp.tool()
|
|
89
|
+
async def ssh_create_folder(host: str, path: str) -> str:
|
|
90
|
+
"""Create a directory on the remote machine. Parents are created as needed (like mkdir -p).
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
host: The target SSH host IP or domain.
|
|
94
|
+
path: The remote path to create.
|
|
95
|
+
"""
|
|
96
|
+
command = f"mkdir -p \"{path}\""
|
|
97
|
+
return await ssh_execute_command(host, command)
|
|
98
|
+
|
|
99
|
+
@mcp.tool()
|
|
100
|
+
async def sftp_upload_file(host: str, local_path: str, remote_path: str) -> str:
|
|
101
|
+
"""Upload a file from the local machine to the remote machine via SFTP.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
host: The target SSH host IP or domain.
|
|
105
|
+
local_path: Absolute path to the file on the local machine.
|
|
106
|
+
remote_path: Absolute or relative path on the remote machine.
|
|
107
|
+
"""
|
|
108
|
+
try:
|
|
109
|
+
if not os.path.isfile(local_path):
|
|
110
|
+
return f"Error: Local file '{local_path}' does not exist."
|
|
111
|
+
|
|
112
|
+
async with await create_connection(host) as conn:
|
|
113
|
+
async with conn.start_sftp_client() as sftp:
|
|
114
|
+
await sftp.put(local_path, remote_path)
|
|
115
|
+
return f"Successfully uploaded '{local_path}' to '{remote_path}' on {host}"
|
|
116
|
+
except Exception as e:
|
|
117
|
+
return f"Error uploading file to {host}: {str(e)}"
|
|
118
|
+
|
|
119
|
+
@mcp.tool()
|
|
120
|
+
async def sftp_download_file(host: str, remote_path: str, local_path: str) -> str:
|
|
121
|
+
"""Download a file from the remote machine to the local machine via SFTP.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
host: The target SSH host IP or domain.
|
|
125
|
+
remote_path: Absolute or relative path on the remote machine.
|
|
126
|
+
local_path: Absolute path to save the file on the local machine.
|
|
127
|
+
"""
|
|
128
|
+
try:
|
|
129
|
+
local_dir = os.path.dirname(local_path)
|
|
130
|
+
if local_dir and not os.path.exists(local_dir):
|
|
131
|
+
os.makedirs(local_dir, exist_ok=True)
|
|
132
|
+
|
|
133
|
+
async with await create_connection(host) as conn:
|
|
134
|
+
async with conn.start_sftp_client() as sftp:
|
|
135
|
+
await sftp.get(remote_path, local_path)
|
|
136
|
+
return f"Successfully downloaded '{remote_path}' from {host} to '{local_path}'"
|
|
137
|
+
except Exception as e:
|
|
138
|
+
return f"Error downloading file from {host}: {str(e)}"
|
|
139
|
+
|
|
140
|
+
@mcp.tool()
|
|
141
|
+
async def sftp_list_directory(host: str, path: str) -> str:
|
|
142
|
+
"""List the contents of a directory on the remote machine via SFTP.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
host: The target SSH host IP or domain.
|
|
146
|
+
path: The remote directory path to list.
|
|
147
|
+
"""
|
|
148
|
+
try:
|
|
149
|
+
async with await create_connection(host) as conn:
|
|
150
|
+
async with conn.start_sftp_client() as sftp:
|
|
151
|
+
files = await sftp.readdir(path)
|
|
152
|
+
|
|
153
|
+
result = []
|
|
154
|
+
for f in files:
|
|
155
|
+
attrs = f.attrs
|
|
156
|
+
size = attrs.size if attrs.size is not None else 0
|
|
157
|
+
result.append(f"{f.filename} (Size: {size} bytes)")
|
|
158
|
+
|
|
159
|
+
if not result:
|
|
160
|
+
return f"Directory '{path}' on {host} is empty."
|
|
161
|
+
return "\\n".join(result)
|
|
162
|
+
except Exception as e:
|
|
163
|
+
return f"Error listing directory on {host}: {str(e)}"
|
|
164
|
+
|
|
165
|
+
def main():
|
|
166
|
+
parser = argparse.ArgumentParser(description="SSH MCP Server")
|
|
167
|
+
parser.add_argument("--servers", help="JSON string containing an array of SSH server configurations")
|
|
168
|
+
|
|
169
|
+
args = parser.parse_args()
|
|
170
|
+
|
|
171
|
+
if args.servers:
|
|
172
|
+
os.environ["SSH_SERVERS"] = args.servers
|
|
173
|
+
|
|
174
|
+
mcp.run(transport='stdio')
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
main()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ssh-mcp-vn
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: High-performance SSH & SFTP MCP Server for Linux
|
|
5
|
+
Author-email: NamHT <namht@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: mcp>=1.2.0
|
|
10
|
+
Requires-Dist: asyncssh>=2.14.0
|
|
11
|
+
Requires-Dist: pydantic>=2.8.0
|
|
12
|
+
Requires-Dist: pydantic-settings>=2.4.0
|
|
13
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
17
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
18
|
+
Requires-Dist: ruff>=0.5.0; extra == "dev"
|
|
19
|
+
Requires-Dist: mypy>=1.10.0; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# SSH & SFTP MCP Server (ssh-mcp-vn)
|
|
22
|
+
|
|
23
|
+
Một MCP (Model Context Protocol) Server mạnh mẽ dùng để thực thi lệnh (SSH) và truyền tải file (SFTP) trên **nhiều máy chủ Linux từ xa (multi-host)** cùng lúc.
|
|
24
|
+
|
|
25
|
+
## Hướng dẫn cài đặt
|
|
26
|
+
|
|
27
|
+
### Chạy qua UVX (Được khuyến nghị)
|
|
28
|
+
Bạn có thể chạy trực tiếp server này qua `uvx` mà không cần phải tải hay cài đặt thủ công:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uvx ssh-mcp-vn
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Các tính năng chính
|
|
35
|
+
|
|
36
|
+
- **Hỗ trợ Multi-host**: Có thể tương tác với nhiều máy chủ Linux mà không cần chạy nhiều instance.
|
|
37
|
+
- **Thực thi qua SSH**: Chạy lệnh bash/shell tùy ý trên máy chủ từ xa.
|
|
38
|
+
- **Quản lý thư mục**: Dễ dàng tạo cấu trúc thư mục từ xa (hoạt động giống lệnh `mkdir -p`).
|
|
39
|
+
- **Tải lên qua SFTP**: Đẩy file từ máy tính cá nhân lên máy chủ từ xa.
|
|
40
|
+
- **Tải về qua SFTP**: Tải file từ máy chủ từ xa về máy tính.
|
|
41
|
+
- **Liệt kê file bằng SFTP**: Xem danh sách các file trong một thư mục bất kỳ trên máy chủ.
|
|
42
|
+
|
|
43
|
+
## Cấu hình
|
|
44
|
+
|
|
45
|
+
MCP server này hỗ trợ nhận cấu hình dạng một chuỗi JSON (JSON string) qua biến môi trường `SSH_SERVERS`. Trong file `mcp_config.json`, bạn cấu hình theo định dạng như sau:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"ssh-server": {
|
|
51
|
+
"command": "uvx",
|
|
52
|
+
"args": [
|
|
53
|
+
"ssh-mcp-vn"
|
|
54
|
+
],
|
|
55
|
+
"env": {
|
|
56
|
+
"SSH_SERVERS": "[{\"host\":\"192.168.1.100\", \"user\":\"root\", \"password\":\"mat_khau_1\", \"port\":22}, {\"host\":\"192.168.1.101\", \"user\":\"ubuntu\", \"key_path\":\"/path/to/key.pem\"}]"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Các trường trong mảng JSON cấu hình
|
|
64
|
+
Trong mảng JSON cấu hình (`SSH_SERVERS`), mỗi object hỗ trợ các trường sau:
|
|
65
|
+
- `host` (bắt buộc): Địa chỉ IP hoặc Hostname của máy chủ SSH.
|
|
66
|
+
- `user` (bắt buộc): Tên đăng nhập (username).
|
|
67
|
+
- `port` (tùy chọn): Cổng SSH, mặc định là 22.
|
|
68
|
+
- `password` (tùy chọn): Mật khẩu đăng nhập.
|
|
69
|
+
- `key_path` (tùy chọn): Đường dẫn tuyệt đối đến file khóa bí mật (private key) nếu dùng key để đăng nhập.
|
|
70
|
+
|
|
71
|
+
## Danh sách công cụ (Tools)
|
|
72
|
+
|
|
73
|
+
*(Tất cả các công cụ đều yêu cầu tham số `host` để hệ thống biết sẽ thao tác trên máy chủ nào).*
|
|
74
|
+
|
|
75
|
+
- `ssh_execute_command`: Chạy một lệnh shell trên máy Linux từ xa.
|
|
76
|
+
- `ssh_create_folder`: Tạo thư mục từ xa.
|
|
77
|
+
- `sftp_upload_file`: Chuyển một file từ local lên máy chủ.
|
|
78
|
+
- `sftp_download_file`: Lấy một file từ máy chủ về local.
|
|
79
|
+
- `sftp_list_directory`: Liệt kê tất cả file trong một thư mục từ xa.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/ssh_mcp_server.py
|
|
4
|
+
src/ssh_mcp_vn.egg-info/PKG-INFO
|
|
5
|
+
src/ssh_mcp_vn.egg-info/SOURCES.txt
|
|
6
|
+
src/ssh_mcp_vn.egg-info/dependency_links.txt
|
|
7
|
+
src/ssh_mcp_vn.egg-info/entry_points.txt
|
|
8
|
+
src/ssh_mcp_vn.egg-info/requires.txt
|
|
9
|
+
src/ssh_mcp_vn.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ssh_mcp_server
|