tunnel-manager 0.0.4__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of tunnel-manager might be problematic. Click here for more details.
- tests/test_tunnel.py +78 -0
- tunnel_manager/__init__.py +22 -7
- tunnel_manager/tunnel_manager.py +770 -69
- tunnel_manager/tunnel_manager_mcp.py +1478 -151
- tunnel_manager-1.0.0.dist-info/METADATA +391 -0
- tunnel_manager-1.0.0.dist-info/RECORD +11 -0
- {tunnel_manager-0.0.4.dist-info → tunnel_manager-1.0.0.dist-info}/entry_points.txt +1 -0
- {tunnel_manager-0.0.4.dist-info → tunnel_manager-1.0.0.dist-info}/top_level.txt +1 -0
- tunnel_manager-0.0.4.dist-info/METADATA +0 -190
- tunnel_manager-0.0.4.dist-info/RECORD +0 -10
- {tunnel_manager-0.0.4.dist-info → tunnel_manager-1.0.0.dist-info}/WHEEL +0 -0
- {tunnel_manager-0.0.4.dist-info → tunnel_manager-1.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tunnel-manager
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI!
|
|
5
|
+
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
8
|
+
Classifier: License :: Public Domain
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: fastmcp>=2.11.3
|
|
16
|
+
Requires-Dist: paramiko>=4.0.0
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# Tunnel Manager
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+

|
|
23
|
+

|
|
24
|
+

|
|
25
|
+

|
|
26
|
+

|
|
27
|
+

|
|
28
|
+
|
|
29
|
+

|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
*Version: 1.0.0*
|
|
42
|
+
|
|
43
|
+
This project provides a Python-based `Tunnel` class for secure SSH connections and file transfers, integrated with a FastMCP server (`tunnel_manager_mcp.py`) to expose these capabilities as tools for AI-driven workflows. The implementation supports both standard SSH (e.g., for local networks) and Teleport's secure access platform, leveraging the `paramiko` library for SSH operations.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
### Tunnel Class
|
|
48
|
+
- **Purpose**: Facilitates secure SSH connections, file transfers, and key management for single or multiple hosts.
|
|
49
|
+
- **Key Functionality**:
|
|
50
|
+
- **Run Remote Commands**: Execute shell commands on a remote host and retrieve output.
|
|
51
|
+
- **File Upload/Download**: Transfer files to/from a single host or all hosts in an inventory group using SFTP.
|
|
52
|
+
- **Passwordless SSH Setup**: Configure key-based authentication for secure, passwordless access.
|
|
53
|
+
- **SSH Config Management**: Copy local SSH config files to remote hosts.
|
|
54
|
+
- **Key Rotation**: Generate and deploy new SSH key pairs, updating `authorized_keys`.
|
|
55
|
+
- **Inventory Support**: Operate on multiple hosts defined in an Ansible-style YAML inventory, with group targeting (e.g., `all`, `homelab`, `poweredge`).
|
|
56
|
+
- **Teleport Support**: Seamlessly integrates with Teleport's certificate-based authentication and proxying.
|
|
57
|
+
- **Configuration Flexibility**: Loads SSH settings from `~/.ssh/config` by default, with optional overrides for username, password, identity files, certificates, and proxy commands.
|
|
58
|
+
- **Logging**: Optional file-based logging for debugging and auditing.
|
|
59
|
+
- **Parallel Execution**: Support for parallel operations across multiple hosts with configurable thread limits.
|
|
60
|
+
|
|
61
|
+
### FastMCP Server
|
|
62
|
+
- **Purpose**: Exposes `Tunnel` class functionality as a FastMCP server, enabling AI tools to perform remote operations programmatically.
|
|
63
|
+
- **Tools Provided**:
|
|
64
|
+
- `run_remote_command`: Runs a shell command on a single remote host.
|
|
65
|
+
- `upload_file`: Uploads a file to a single remote host via SFTP.
|
|
66
|
+
- `download_file`: Downloads a file from a single remote host via SFTP.
|
|
67
|
+
- `check_ssh_server`: Checks if the SSH server is running and configured for key-based authentication.
|
|
68
|
+
- `test_key_auth`: Tests key-based authentication for a host.
|
|
69
|
+
- `setup_passwordless_ssh`: Sets up passwordless SSH for a single host.
|
|
70
|
+
- `copy_ssh_config`: Copies an SSH config file to a single remote host.
|
|
71
|
+
- `rotate_ssh_key`: Rotates SSH keys for a single host.
|
|
72
|
+
- `remove_host_key`: Removes a host’s key from the local `known_hosts` file.
|
|
73
|
+
- `setup_all_passwordless_ssh`: Sets up passwordless SSH for all hosts in an inventory group.
|
|
74
|
+
- `run_command_on_all`: Runs a command on all hosts in an inventory group.
|
|
75
|
+
- `copy_ssh_config_on_all`: Copies an SSH config file to all hosts in an inventory group.
|
|
76
|
+
- `rotate_ssh_key_on_all`: Rotates SSH keys for all hosts in an inventory group.
|
|
77
|
+
- **Transport Options**: Supports `stdio` (for local scripting) and `http` (for networked access) transport modes.
|
|
78
|
+
- **Progress Reporting**: Integrates with FastMCP's `Context` for progress updates during operations.
|
|
79
|
+
- **Logging**: Comprehensive logging to a file (`tunnel_mcp.log` by default) or a user-specified file.
|
|
80
|
+
|
|
81
|
+
<details>
|
|
82
|
+
<summary><b>Usage:</b></summary>
|
|
83
|
+
|
|
84
|
+
## Tunnel Class
|
|
85
|
+
The `Tunnel` class can be used standalone for SSH operations. Example:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from tunnel_manager.tunnel_manager import Tunnel
|
|
89
|
+
|
|
90
|
+
# Initialize with a remote host (assumes ~/.ssh/config or explicit params)
|
|
91
|
+
tunnel = Tunnel(
|
|
92
|
+
remote_host="192.168.1.10",
|
|
93
|
+
username="admin",
|
|
94
|
+
password="mypassword",
|
|
95
|
+
identity_file="/path/to/id_rsa",
|
|
96
|
+
certificate_file="/path/to/cert", # Optional for Teleport
|
|
97
|
+
proxy_command="tsh proxy ssh %h", # Optional for Teleport
|
|
98
|
+
ssh_config_file="~/.ssh/config",
|
|
99
|
+
log_file="tunnel.log"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Connect and run a command
|
|
103
|
+
tunnel.connect()
|
|
104
|
+
out, err = tunnel.run_command("ls -la /tmp")
|
|
105
|
+
print(f"Output: {out}\nError: {err}")
|
|
106
|
+
|
|
107
|
+
# Upload a file
|
|
108
|
+
tunnel.send_file("/local/file.txt", "/remote/file.txt")
|
|
109
|
+
|
|
110
|
+
# Download a file
|
|
111
|
+
tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
|
|
112
|
+
|
|
113
|
+
# Setup passwordless SSH
|
|
114
|
+
tunnel.setup_passwordless_ssh(local_key_path="~/.ssh/id_rsa")
|
|
115
|
+
|
|
116
|
+
# Copy SSH config
|
|
117
|
+
tunnel.copy_ssh_config("/local/ssh_config", "~/.ssh/config")
|
|
118
|
+
|
|
119
|
+
# Rotate SSH key
|
|
120
|
+
tunnel.rotate_ssh_key("/path/to/new_key")
|
|
121
|
+
|
|
122
|
+
# Close the connection
|
|
123
|
+
tunnel.close()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Tunnel Manager CLI Usage
|
|
127
|
+
The `tunnel_manager.py` script provides a CLI for managing SSH operations across hosts defined in an Ansible-style YAML inventory file. Below are examples for each command, targeting different inventory groups (`all`, `homelab`, `poweredge`).
|
|
128
|
+
|
|
129
|
+
**Inventory File Example (`inventory.yml`)**:
|
|
130
|
+
```yaml
|
|
131
|
+
all:
|
|
132
|
+
hosts:
|
|
133
|
+
r510:
|
|
134
|
+
ansible_host: 192.168.1.10
|
|
135
|
+
ansible_user: admin
|
|
136
|
+
ansible_ssh_pass: mypassword
|
|
137
|
+
r710:
|
|
138
|
+
ansible_host: 192.168.1.11
|
|
139
|
+
ansible_user: admin
|
|
140
|
+
ansible_ssh_pass: mypassword
|
|
141
|
+
gr1080:
|
|
142
|
+
ansible_host: 192.168.1.14
|
|
143
|
+
ansible_user: admin
|
|
144
|
+
ansible_ssh_pass: mypassword
|
|
145
|
+
homelab:
|
|
146
|
+
hosts:
|
|
147
|
+
r510:
|
|
148
|
+
ansible_host: 192.168.1.10
|
|
149
|
+
ansible_user: admin
|
|
150
|
+
ansible_ssh_pass: mypassword
|
|
151
|
+
r710:
|
|
152
|
+
ansible_host: 192.168.1.11
|
|
153
|
+
ansible_user: admin
|
|
154
|
+
ansible_ssh_pass: mypassword
|
|
155
|
+
gr1080:
|
|
156
|
+
ansible_host: 192.168.1.14
|
|
157
|
+
ansible_user: admin
|
|
158
|
+
ansible_ssh_pass: mypassword
|
|
159
|
+
poweredge:
|
|
160
|
+
hosts:
|
|
161
|
+
r510:
|
|
162
|
+
ansible_host: 192.168.1.10
|
|
163
|
+
ansible_user: admin
|
|
164
|
+
ansible_ssh_pass: mypassword
|
|
165
|
+
r710:
|
|
166
|
+
ansible_host: 192.168.1.11
|
|
167
|
+
ansible_user: admin
|
|
168
|
+
ansible_ssh_pass: mypassword
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Replace IPs, usernames, and passwords with your actual values.
|
|
172
|
+
|
|
173
|
+
### CLI Commands
|
|
174
|
+
|
|
175
|
+
#### 1. Setup Passwordless SSH
|
|
176
|
+
Set up passwordless SSH for hosts in the inventory, distributing a shared key.
|
|
177
|
+
- **Target `all` group (sequential)**:
|
|
178
|
+
```bash
|
|
179
|
+
tunnel-manager setup-all --inventory inventory.yml --shared-key-path ~/.ssh/id_shared --log-file setup.log
|
|
180
|
+
```
|
|
181
|
+
- **Target `homelab` group (parallel, 3 threads)**:
|
|
182
|
+
```bash
|
|
183
|
+
tunnel-manager setup-all --inventory inventory.yml --shared-key-path ~/.ssh/id_shared --group homelab --parallel --max-threads 3 --log-file setup_homelab.log
|
|
184
|
+
```
|
|
185
|
+
- **Target `poweredge` group (sequential)**:
|
|
186
|
+
```bash
|
|
187
|
+
tunnel-manager setup-all --inventory inventory.yml --shared-key-path ~/.ssh/id_shared --group poweredge --log-file setup_poweredge.log
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### 2. Run a Command
|
|
191
|
+
Execute a shell command on all hosts in the specified group.
|
|
192
|
+
- **Run `uptime` on `all` group (sequential)**:
|
|
193
|
+
```bash
|
|
194
|
+
tunnel-manager run-command --inventory inventory.yml --remote-command "uptime" --log-file uptime.log
|
|
195
|
+
```
|
|
196
|
+
- **Run `df -h` on `homelab` group (parallel, 5 threads)**:
|
|
197
|
+
```bash
|
|
198
|
+
tunnel-manager run-command --inventory inventory.yml --remote-command "df -h" --group homelab --parallel --max-threads 5 --log-file df_homelab.log
|
|
199
|
+
```
|
|
200
|
+
- **Run `whoami` on `poweredge` group (sequential)**:
|
|
201
|
+
```bash
|
|
202
|
+
tunnel-manager run-command --inventory inventory.yml --remote-command "whoami" --group poweredge --log-file whoami_poweredge.log
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### 3. Copy SSH Config
|
|
206
|
+
Copy a local SSH config file to the remote hosts’ `~/.ssh/config`.
|
|
207
|
+
- **Copy to `all` group (sequential)**:
|
|
208
|
+
```bash
|
|
209
|
+
tunnel-manager copy-config --inventory inventory.yml --local-config-path ~/.ssh/config --log-file copy_config.log
|
|
210
|
+
```
|
|
211
|
+
- **Copy to `homelab` group (parallel, 4 threads)**:
|
|
212
|
+
```bash
|
|
213
|
+
tunnel-manager copy-config --inventory inventory.yml --local-config-path ~/.ssh/config --group homelab --parallel --max-threads 4 --log-file copy_homelab.log
|
|
214
|
+
```
|
|
215
|
+
- **Copy to `poweredge` group with custom remote path**:
|
|
216
|
+
```bash
|
|
217
|
+
tunnel-manager copy-config --inventory inventory.yml --local-config-path ~/.ssh/config --remote-config-path ~/.ssh/custom_config --group poweredge --log-file copy_poweredge.log
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
#### 4. Rotate SSH Keys
|
|
221
|
+
Rotate SSH keys for hosts, generating new keys with a prefix.
|
|
222
|
+
- **Rotate keys for `all` group (sequential)**:
|
|
223
|
+
```bash
|
|
224
|
+
tunnel-manager rotate-key --inventory inventory.yml --key-prefix ~/.ssh/id_ --log-file rotate.log
|
|
225
|
+
```
|
|
226
|
+
- **Rotate keys for `homelab` group (parallel, 3 threads)**:
|
|
227
|
+
```bash
|
|
228
|
+
tunnel-manager rotate-key --inventory inventory.yml --key-prefix ~/.ssh/id_ --group homelab --parallel --max-threads 3 --log-file rotate_homelab.log
|
|
229
|
+
```
|
|
230
|
+
- **Rotate keys for `poweredge` group (sequential)**:
|
|
231
|
+
```bash
|
|
232
|
+
tunnel-manager rotate-key --inventory inventory.yml --key-prefix ~/.ssh/id_ --group poweredge --log-file rotate_poweredge.log
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### 5. Upload a File
|
|
236
|
+
Upload a local file to all hosts in the specified group.
|
|
237
|
+
- **Upload to `all` group (sequential)**:
|
|
238
|
+
```bash
|
|
239
|
+
tunnel-manager send-file --inventory inventory.yml --local-path ./myfile.txt --remote-path /home/user/myfile.txt --log-file upload.log
|
|
240
|
+
```
|
|
241
|
+
- **Upload to `homelab` group (parallel, 3 threads)**:
|
|
242
|
+
```bash
|
|
243
|
+
tunnel-manager send-file --inventory inventory.yml --local-path ./myfile.txt --remote-path /home/user/myfile.txt --group homelab --parallel --max-threads 3 --log-file upload_homelab.log
|
|
244
|
+
```
|
|
245
|
+
- **Upload to `poweredge` group (sequential)**:
|
|
246
|
+
```bash
|
|
247
|
+
tunnel-manager send-file --inventory inventory.yml --local-path ./myfile.txt --remote-path /home/user/myfile.txt --group poweredge --log-file upload_poweredge.log
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### 6. Download a File
|
|
251
|
+
Download a file from all hosts in the specified group, saving to host-specific subdirectories (e.g., `downloads/R510/myfile.txt`).
|
|
252
|
+
- **Download from `all` group (sequential)**:
|
|
253
|
+
```bash
|
|
254
|
+
tunnel-manager receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --log-file download.log
|
|
255
|
+
```
|
|
256
|
+
- **Download from `homelab` group (parallel, 3 threads)**:
|
|
257
|
+
```bash
|
|
258
|
+
tunnel-manager receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --group homelab --parallel --max-threads 3 --log-file download_homelab.log
|
|
259
|
+
```
|
|
260
|
+
- **Download from `poweredge` group (sequential)**:
|
|
261
|
+
```bash
|
|
262
|
+
tunnel-manager receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --group poweredge --log-file download_poweredge.log
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### CLI Command Table
|
|
266
|
+
| Short Flag | Long Flag | Description | Required | Default Value |
|
|
267
|
+
|------------|----------------------|----------------------------------------------------------|----------|---------------|
|
|
268
|
+
| -h | --help | Show usage for the script | No | None |
|
|
269
|
+
| | --log-file | Log to specified file (default: console output) | No | Console |
|
|
270
|
+
| | setup-all | Setup passwordless SSH for all hosts in inventory | Yes* | None |
|
|
271
|
+
| | --inventory | YAML inventory path | Yes | None |
|
|
272
|
+
| | --shared-key-path | Path to shared private key | No | ~/.ssh/id_shared |
|
|
273
|
+
| | --group | Inventory group to target | No | all |
|
|
274
|
+
| | --parallel | Run operation in parallel | No | False |
|
|
275
|
+
| | --max-threads | Max threads for parallel execution | No | 5 |
|
|
276
|
+
| | run-command | Run a shell command on all hosts in inventory | Yes* | None |
|
|
277
|
+
| | --remote-command | Shell command to run | Yes | None |
|
|
278
|
+
| | copy-config | Copy SSH config to all hosts in inventory | Yes* | None |
|
|
279
|
+
| | --local-config-path | Local SSH config path | Yes | None |
|
|
280
|
+
| | --remote-config-path | Remote path for SSH config | No | ~/.ssh/config |
|
|
281
|
+
| | rotate-key | Rotate SSH keys for all hosts in inventory | Yes* | None |
|
|
282
|
+
| | --key-prefix | Prefix for new key paths (appends hostname) | No | ~/.ssh/id_ |
|
|
283
|
+
| | send-file | Upload a file to all hosts in inventory | Yes* | None |
|
|
284
|
+
| | --local-path | Local file path to upload | Yes | None |
|
|
285
|
+
| | --remote-path | Remote destination path | Yes | None |
|
|
286
|
+
| | receive-file | Download a file from all hosts in inventory | Yes* | None |
|
|
287
|
+
| | --remote-path | Remote file path to download | Yes | None |
|
|
288
|
+
| | --local-path-prefix | Local directory path prefix to save files | Yes | None |
|
|
289
|
+
|
|
290
|
+
### Notes
|
|
291
|
+
One of the commands (`setup-all`, `run-command`, `copy-config`, `rotate-key`, `send-file`, `receive-file`) must be specified as the first argument to `tunnel_manager.py`. Each command has required arguments that must be specified with flags:
|
|
292
|
+
- `setup-all`: Requires `--inventory`.
|
|
293
|
+
- `run-command`: Requires `--inventory` and `--remote-command`.
|
|
294
|
+
- `copy-config`: Requires `--inventory` and `--local-config-path`.
|
|
295
|
+
- `rotate-key`: Requires `--inventory`.
|
|
296
|
+
- `send-file`: Requires `--inventory`, `--local-path`, and `--remote-path`.
|
|
297
|
+
- `receive-file`: Requires `--inventory`, `--remote-path`, and `--local-path-prefix`.
|
|
298
|
+
|
|
299
|
+
### Additional Notes
|
|
300
|
+
- Ensure `ansible_host` values in `inventory.yml` are resolvable IPs or hostnames.
|
|
301
|
+
- Update `ansible_ssh_private_key_file` in the inventory after running `rotate-key`.
|
|
302
|
+
- Use `--log-file` for file-based logging or omit for console output.
|
|
303
|
+
- The `--parallel` option speeds up operations but may overload resources; adjust `--max-threads` as needed.
|
|
304
|
+
- The `receive-file` command saves files to `local_path_prefix/<hostname>/<filename>` to preserve original filenames and avoid conflicts.
|
|
305
|
+
|
|
306
|
+
## FastMCP Server
|
|
307
|
+
The FastMCP server exposes the `Tunnel` functionality as AI-accessible tools. Start the server with:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
python tunnel_manager_mcp.py --transport stdio
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Or for HTTP transport:
|
|
314
|
+
```bash
|
|
315
|
+
python tunnel_manager_mcp.py --transport http --host 127.0.0.1 --port 8080
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
</details>
|
|
319
|
+
|
|
320
|
+
<details>
|
|
321
|
+
<summary><b>Installation Instructions:</b></summary>
|
|
322
|
+
|
|
323
|
+
## Use with AI
|
|
324
|
+
|
|
325
|
+
Configure `mcp.json`
|
|
326
|
+
```json
|
|
327
|
+
{
|
|
328
|
+
"mcpServers": {
|
|
329
|
+
"tunnel_manager": {
|
|
330
|
+
"command": "uv",
|
|
331
|
+
"args": [
|
|
332
|
+
"run",
|
|
333
|
+
"--with",
|
|
334
|
+
"tunnel-manager",
|
|
335
|
+
"tunnel_manager_mcp"
|
|
336
|
+
],
|
|
337
|
+
"env": {
|
|
338
|
+
"TUNNEL_REMOTE_HOST": "user@192.168.1.12", // Optional
|
|
339
|
+
"TUNNEL_USERNAME": "admin", // Optional
|
|
340
|
+
"TUNNEL_PASSWORD": "", // Optional
|
|
341
|
+
"TUNNEL_REMOTE_PORT": "22", // Optional
|
|
342
|
+
"TUNNEL_IDENTITY_FILE": "", // Optional
|
|
343
|
+
"TUNNEL_CERTIFICATE": "", // Optional
|
|
344
|
+
"TUNNEL_PROXY_COMMAND": "", // Optional
|
|
345
|
+
"TUNNEL_LOG_FILE": "~/tunnel_log.txt" // Optional
|
|
346
|
+
},
|
|
347
|
+
"timeout": 200000
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Deploy MCP Server as a Container
|
|
354
|
+
```bash
|
|
355
|
+
docker pull knucklessg1/tunnel-manager:latest
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Modify the `compose.yml`
|
|
359
|
+
```yaml
|
|
360
|
+
services:
|
|
361
|
+
tunnel-manager:
|
|
362
|
+
image: knucklessg1/tunnel-manager:latest
|
|
363
|
+
environment:
|
|
364
|
+
- HOST=0.0.0.0
|
|
365
|
+
- PORT=8021
|
|
366
|
+
ports:
|
|
367
|
+
- 8021:8021
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Install Python Package
|
|
371
|
+
```bash
|
|
372
|
+
python -m pip install tunnel-manager
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
or
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
uv pip install --upgrade tunnel-manager
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
</details>
|
|
382
|
+
|
|
383
|
+
<details>
|
|
384
|
+
<summary><b>Repository Owners:</b></summary>
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
388
|
+
|
|
389
|
+

|
|
390
|
+

|
|
391
|
+
</details>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
tests/test_tunnel.py,sha256=_IYZ4XnTgJckdigi6kWm2g0omnNvMGyCXpTwPOjVrow,2500
|
|
2
|
+
tunnel_manager/__init__.py,sha256=cqAitAkoCcEkaCQcP7Y8tngiUK7pU6SIMlmpABShh9g,807
|
|
3
|
+
tunnel_manager/__main__.py,sha256=Z1uxNLjwIjJpvu97bXrvsawnghJScA52E2wtAgg5MLo,152
|
|
4
|
+
tunnel_manager/tunnel_manager.py,sha256=0CQ9N7l3hB3QawNA5AB1G55NRtV-c5Mq1c56EQQtt3c,35026
|
|
5
|
+
tunnel_manager/tunnel_manager_mcp.py,sha256=lcjmsuT4H3rhGVj-X8IyYINCPcKZ559K0iYiaK8iKfw,57419
|
|
6
|
+
tunnel_manager-1.0.0.dist-info/licenses/LICENSE,sha256=Z1xmcrPHBnGCETO_LLQJUeaSNBSnuptcDVTt4kaPUOE,1060
|
|
7
|
+
tunnel_manager-1.0.0.dist-info/METADATA,sha256=62UzKmIayq1M6IUO73g9P49_7ivVkpqEnPov9IV3YYc,18280
|
|
8
|
+
tunnel_manager-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
+
tunnel_manager-1.0.0.dist-info/entry_points.txt,sha256=hYtm4jvOAew8CbeqqUBH2nXY51mSQwhF4GhU0yclV6c,154
|
|
10
|
+
tunnel_manager-1.0.0.dist-info/top_level.txt,sha256=W4J-lyPPNeOS696f0LneZsP2MVERR8HE9UHbAFQ550A,21
|
|
11
|
+
tunnel_manager-1.0.0.dist-info/RECORD,,
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: tunnel-manager
|
|
3
|
-
Version: 0.0.4
|
|
4
|
-
Summary: Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI!
|
|
5
|
-
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
8
|
-
Classifier: License :: Public Domain
|
|
9
|
-
Classifier: Environment :: Console
|
|
10
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Requires-Python: >=3.10
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: fastmcp>=2.11.3
|
|
16
|
-
Requires-Dist: paramiko>=4.0.0
|
|
17
|
-
Dynamic: license-file
|
|
18
|
-
|
|
19
|
-
# Tunnel Manager
|
|
20
|
-
|
|
21
|
-

|
|
22
|
-

|
|
23
|
-

|
|
24
|
-

|
|
25
|
-

|
|
26
|
-

|
|
27
|
-

|
|
28
|
-
|
|
29
|
-

|
|
30
|
-

|
|
31
|
-

|
|
32
|
-

|
|
33
|
-
|
|
34
|
-

|
|
35
|
-

|
|
36
|
-

|
|
37
|
-

|
|
38
|
-

|
|
39
|
-

|
|
40
|
-
|
|
41
|
-
*Version: 0.0.4*
|
|
42
|
-
|
|
43
|
-
This project provides a Python-based `Tunnel` class for secure SSH connections and file transfers,
|
|
44
|
-
integrated with a FastMCP server (`tunnel_mcp.py`) to expose these capabilities as tools for AI-driven workflows.
|
|
45
|
-
The implementation supports both standard SSH (e.g., for local networks) and
|
|
46
|
-
Teleport's secure access platform, leveraging the `paramiko` library for SSH operations.
|
|
47
|
-
|
|
48
|
-
## Features
|
|
49
|
-
|
|
50
|
-
### Tunnel Class
|
|
51
|
-
- **Purpose**: Facilitates secure SSH connections and file transfers to remote hosts.
|
|
52
|
-
- **Key Functionality**:
|
|
53
|
-
- **Run Remote Commands**: Execute shell commands on a remote host and retrieve output.
|
|
54
|
-
- **File Upload/Download**: Transfer files to/from a remote host using SFTP.
|
|
55
|
-
- **Teleport Support**: Seamlessly integrates with Teleport's certificate-based authentication and proxying.
|
|
56
|
-
- **Configuration Flexibility**: Loads SSH settings from `~/.ssh/config` by default, with optional overrides for identity files, certificates, and proxy commands.
|
|
57
|
-
- **Logging**: Optional file-based logging for debugging and auditing.
|
|
58
|
-
|
|
59
|
-
### FastMCP Server
|
|
60
|
-
- **Purpose**: Exposes `Tunnel` class functionality as a FastMCP server, enabling AI tools to perform remote operations programmatically.
|
|
61
|
-
- **Tools Provided**:
|
|
62
|
-
- `run_remote_command`: Runs a shell command on a remote host and returns output.
|
|
63
|
-
- `upload_file`: Uploads a file to a remote host via SFTP.
|
|
64
|
-
- `download_file`: Downloads a file from a remote host via SFTP.
|
|
65
|
-
- **Transport Options**: Supports `stdio` (for local scripting) and `http` (for networked access) transport modes.
|
|
66
|
-
- **Progress Reporting**: Integrates with FastMCP's `Context` for progress updates during operations.
|
|
67
|
-
- **Logging**: Comprehensive logging to a file (`tunnel_mcp.log` by default).
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
<details>
|
|
71
|
-
<summary><b>Usage:</b></summary>
|
|
72
|
-
|
|
73
|
-
## Tunnel Class
|
|
74
|
-
The `Tunnel` class can be used standalone for SSH operations. Example:
|
|
75
|
-
|
|
76
|
-
```python
|
|
77
|
-
from tunnel_manager import Tunnel
|
|
78
|
-
|
|
79
|
-
# Initialize with a remote host (assumes ~/.ssh/config or explicit params)
|
|
80
|
-
tunnel = Tunnel(
|
|
81
|
-
remote_host="example.com",
|
|
82
|
-
identity_file="/path/to/id_rsa",
|
|
83
|
-
certificate_file="/path/to/cert", # Optional for Teleport
|
|
84
|
-
proxy_command="tsh proxy ssh %h", # Optional for Teleport
|
|
85
|
-
log_file="tunnel.log"
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
# Connect and run a command
|
|
89
|
-
tunnel.connect()
|
|
90
|
-
out, err = tunnel.run_command("ls -la /tmp")
|
|
91
|
-
print(f"Output: {out}\nError: {err}")
|
|
92
|
-
|
|
93
|
-
# Upload a file
|
|
94
|
-
tunnel.send_file("/local/file.txt", "/remote/file.txt")
|
|
95
|
-
|
|
96
|
-
# Download a file
|
|
97
|
-
tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
|
|
98
|
-
|
|
99
|
-
# Close the connection
|
|
100
|
-
tunnel.close()
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
## FastMCP Server
|
|
105
|
-
The FastMCP server exposes the `Tunnel` functionality as AI-accessible tools. Start the server with:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
python tunnel_mcp.py --transport stdio
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Or for HTTP transport:
|
|
112
|
-
```bash
|
|
113
|
-
python tunnel_mcp.py --transport http --host 127.0.0.1 --port 8080
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
</details>
|
|
117
|
-
|
|
118
|
-
<details>
|
|
119
|
-
<summary><b>Installation Instructions:</b></summary>
|
|
120
|
-
|
|
121
|
-
## Use with AI
|
|
122
|
-
|
|
123
|
-
Configure `mcp.json`
|
|
124
|
-
```json
|
|
125
|
-
{
|
|
126
|
-
"mcpServers": {
|
|
127
|
-
"tunnel_manager": {
|
|
128
|
-
"command": "uv",
|
|
129
|
-
"args": [
|
|
130
|
-
"run",
|
|
131
|
-
"--with",
|
|
132
|
-
"tunnel-manager",
|
|
133
|
-
"tunnel-manager-mcp"
|
|
134
|
-
],
|
|
135
|
-
"env": {
|
|
136
|
-
"TUNNEL_REMOTE_HOST": "user@192.168.1.12", // Optional
|
|
137
|
-
"TUNNEL_REMOTE_PORT": "22", // Optional
|
|
138
|
-
"TUNNEL_IDENTITY_FILE": "", // Optional
|
|
139
|
-
"TUNNEL_CERTIFICATE": "", // Optional
|
|
140
|
-
"TUNNEL_PROXY_COMMAND": "", // Optional
|
|
141
|
-
"TUNNEL_LOG_FILE": "~./tunnel_log.txt" // Optional
|
|
142
|
-
},
|
|
143
|
-
"timeout": 200000
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Deploy MCP Server as a container
|
|
150
|
-
```bash
|
|
151
|
-
docker pull knucklessg1/tunnel-manager:latest
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
Modify the `compose.yml`
|
|
155
|
-
|
|
156
|
-
```compose
|
|
157
|
-
services:
|
|
158
|
-
tunnel-manager:
|
|
159
|
-
image: knucklessg1/tunnel-manager:latest
|
|
160
|
-
environment:
|
|
161
|
-
- HOST=0.0.0.0
|
|
162
|
-
- PORT=8021
|
|
163
|
-
ports:
|
|
164
|
-
- 8021:8021
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Install Python Package
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
python -m pip install tunnel-manager
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
or
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
uv pip install --upgrade tunnel-manager
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</details>
|
|
181
|
-
|
|
182
|
-
<details>
|
|
183
|
-
<summary><b>Repository Owners:</b></summary>
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
187
|
-
|
|
188
|
-

|
|
189
|
-

|
|
190
|
-
</details>
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
tunnel_manager/__init__.py,sha256=9I_qajRiMP4bxiKdEIx0bKIeTg8b4x1TsYnTMfbWIJA,273
|
|
2
|
-
tunnel_manager/__main__.py,sha256=Z1uxNLjwIjJpvu97bXrvsawnghJScA52E2wtAgg5MLo,152
|
|
3
|
-
tunnel_manager/tunnel_manager.py,sha256=_MokYwLLe0ekQA1CeAaH_4JTRx0TctGUJLwai3MIQvc,6565
|
|
4
|
-
tunnel_manager/tunnel_manager_mcp.py,sha256=ZYhmenIaApFBHMKDh05zxk6NffYw0yI67flt30VFDfQ,10568
|
|
5
|
-
tunnel_manager-0.0.4.dist-info/licenses/LICENSE,sha256=Z1xmcrPHBnGCETO_LLQJUeaSNBSnuptcDVTt4kaPUOE,1060
|
|
6
|
-
tunnel_manager-0.0.4.dist-info/METADATA,sha256=mlzpt0cG9fHhIjytOZwLOo62getfNqPwld7JrdPCK4A,6568
|
|
7
|
-
tunnel_manager-0.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
-
tunnel_manager-0.0.4.dist-info/entry_points.txt,sha256=mxjinmmRNDVn_VbKHi63vkSvj7pp8btUKFQeXLm4-WY,92
|
|
9
|
-
tunnel_manager-0.0.4.dist-info/top_level.txt,sha256=AlbS1pBPQr8wIlDsmwNxGDLK4L4s4CY_X9AellT3-x8,15
|
|
10
|
-
tunnel_manager-0.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|