sshand 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.
sshand-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Murad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
sshand-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,344 @@
1
+ Metadata-Version: 2.4
2
+ Name: sshand
3
+ Version: 0.1.0
4
+ Summary: MCP server — give any AI agent SSH access to remote Linux/Unix machines
5
+ License: MIT License
6
+
7
+ Copyright (c) 2025 Murad
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
27
+ Project-URL: Homepage, https://github.com/muradmalik23/sshand
28
+ Project-URL: Repository, https://github.com/muradmalik23/sshand
29
+ Project-URL: Issues, https://github.com/muradmalik23/sshand/issues
30
+ Project-URL: Changelog, https://github.com/muradmalik23/sshand/blob/main/CHANGELOG.md
31
+ Keywords: mcp,ssh,ai,agent,claude,openai,llm,sshand
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Intended Audience :: System Administrators
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Topic :: System :: Systems Administration
41
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
42
+ Requires-Python: >=3.10
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Requires-Dist: mcp[cli]>=1.6.0
46
+ Requires-Dist: paramiko>=3.4.0
47
+ Requires-Dist: pyyaml>=6.0
48
+ Requires-Dist: pydantic>=2.7.0
49
+ Provides-Extra: dev
50
+ Requires-Dist: pytest>=8.0; extra == "dev"
51
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
52
+ Dynamic: license-file
53
+
54
+ # SSHand
55
+
56
+ An open MCP server that gives **any AI agent** SSH access to remote Linux/Unix machines — shell commands, file read/write, and SFTP transfers.
57
+
58
+ Works with **Claude.ai**, **Claude Desktop**, **ChatGPT**, **Cursor**, **VS Code Copilot**, **OpenAI Agents SDK**, and any other [MCP-compatible client](https://modelcontextprotocol.io/clients).
59
+
60
+ ---
61
+
62
+ ## Quick start
63
+
64
+ ```bash
65
+ # 1. Install
66
+ pip install sshand
67
+
68
+ # 2. Run the interactive setup wizard
69
+ sshand setup
70
+ ```
71
+
72
+ The wizard walks you through adding your first host, testing the connection, and copying the right config snippet for whichever AI client you use.
73
+
74
+ ---
75
+
76
+ ## Installation options
77
+
78
+ ### Option A — pip (recommended for most users)
79
+
80
+ ```bash
81
+ pip install sshand # from PyPI
82
+ pip install -e . # from source, editable install
83
+ ```
84
+
85
+ ### Option B — uvx (zero-install, no venv needed)
86
+
87
+ [uv](https://docs.astral.sh/uv/) is the modern Python package manager. With it installed you can run SSHand without any manual install step:
88
+
89
+ ```bash
90
+ uvx sshand # run server directly
91
+ uvx sshand setup # run setup wizard
92
+ ```
93
+
94
+ This is the cleanest option to recommend to non-technical users.
95
+
96
+ ### Option C — plain Python (no install)
97
+
98
+ ```bash
99
+ git clone https://github.com/YOUR_GITHUB_USERNAME/sshand
100
+ cd sshand
101
+ pip install -r requirements.txt
102
+ python server.py # start server
103
+ python setup_wizard.py # run wizard
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Connecting to your AI client
109
+
110
+ ### Claude.ai and ChatGPT (web + desktop)
111
+
112
+ For Claude.ai web and ChatGPT, SSHand runs as an **HTTP server** and you connect it through each app's native integrations UI.
113
+
114
+ **→ See [INTEGRATIONS.md](INTEGRATIONS.md) for the full step-by-step guide**, including how to expose the server publicly using ngrok or Cloudflare Tunnel, and how to add it to Claude.ai Integrations and ChatGPT Desktop.
115
+
116
+ ---
117
+
118
+ ### Claude Desktop
119
+
120
+ Add to your `claude_desktop_config.json`:
121
+
122
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
123
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
124
+
125
+ ```json
126
+ {
127
+ "mcpServers": {
128
+ "ssh": {
129
+ "command": "uvx",
130
+ "args": ["sshand"],
131
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ Or with plain Python:
138
+
139
+ ```json
140
+ {
141
+ "mcpServers": {
142
+ "ssh": {
143
+ "command": "python",
144
+ "args": ["/absolute/path/to/sshand/server.py"],
145
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/sshand/hosts.yaml" }
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ Restart Claude Desktop after saving.
152
+
153
+ ---
154
+
155
+ ### Cursor
156
+
157
+ Create or update `.cursor/mcp.json` in your project (or the global Cursor MCP settings):
158
+
159
+ ```json
160
+ {
161
+ "mcpServers": {
162
+ "ssh": {
163
+ "command": "uvx",
164
+ "args": ["sshand"],
165
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ### VS Code (GitHub Copilot Chat)
174
+
175
+ Add to `.vscode/mcp.json` or your workspace `settings.json`:
176
+
177
+ ```json
178
+ {
179
+ "mcp": {
180
+ "servers": {
181
+ "ssh": {
182
+ "type": "stdio",
183
+ "command": "uvx",
184
+ "args": ["sshand"],
185
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }
186
+ }
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ### OpenAI Agents SDK
195
+
196
+ ```bash
197
+ # Terminal 1 — keep this running
198
+ sshand --transport http --port 8000
199
+ ```
200
+
201
+ ```python
202
+ from agents import Agent
203
+ from agents.mcp import MCPServerStreamableHttp
204
+
205
+ ssh_server = MCPServerStreamableHttp(url="http://localhost:8000/mcp")
206
+ agent = Agent(name="ops-agent", mcp_servers=[ssh_server])
207
+ ```
208
+
209
+ ---
210
+
211
+ ### Any other MCP client (HTTP)
212
+
213
+ ```bash
214
+ sshand --transport http --port 8000
215
+ ```
216
+
217
+ MCP endpoint: `http://localhost:8000/mcp`
218
+
219
+ For remote access, put a reverse proxy (nginx / Caddy) in front with TLS. Never expose port 8000 directly on a public interface.
220
+
221
+ ---
222
+
223
+ ## Host inventory
224
+
225
+ Hosts are stored in `hosts.yaml` (set a different path with the `SSH_MCP_HOSTS_FILE` env var). You can edit the file directly or let your agent call `ssh_add_host`.
226
+
227
+ Copy `hosts.yaml.example` to `hosts.yaml` to get started:
228
+
229
+ ```bash
230
+ cp hosts.yaml.example hosts.yaml
231
+ ```
232
+
233
+ ### Auth types
234
+
235
+ **Key file** — most common, most secure:
236
+ ```yaml
237
+ auth:
238
+ type: key
239
+ key_path: ~/.ssh/id_rsa # ~ is expanded automatically
240
+ passphrase: null # set if the key is encrypted
241
+ ```
242
+
243
+ **Password** — convenient for dev/test, avoid on internet-facing servers:
244
+ ```yaml
245
+ auth:
246
+ type: password
247
+ password: s3cr3t
248
+ ```
249
+
250
+ **SSH agent** — no credentials stored at all, delegates to the running `ssh-agent`:
251
+ ```yaml
252
+ auth:
253
+ type: agent
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Available tools
259
+
260
+ | Tool | Description | Read-only? |
261
+ |------|-------------|------------|
262
+ | `ssh_list_hosts` | List all configured SSH targets | ✅ |
263
+ | `ssh_add_host` | Register a new SSH host | ❌ |
264
+ | `ssh_remove_host` | Remove a host from inventory | ❌ |
265
+ | `ssh_test_connection` | Verify auth works for a host | ✅ |
266
+ | `ssh_run_command` | Execute a shell command + capture output | ❌ |
267
+ | `ssh_read_file` | Read a remote file's contents | ✅ |
268
+ | `ssh_write_file` | Create or overwrite a remote file | ❌ |
269
+ | `ssh_list_directory` | Browse a remote directory | ✅ |
270
+ | `ssh_upload_file` | Push a local file to the remote host (SFTP) | ❌ |
271
+ | `ssh_download_file` | Pull a remote file to this machine (SFTP) | ✅ |
272
+ | `ssh_get_local_info` | Return OS and path style of the MCP server host | ✅ |
273
+
274
+ ---
275
+
276
+ ## Example conversations
277
+
278
+ > *"What servers do you have access to?"*
279
+ > → `ssh_list_hosts`
280
+
281
+ > *"Check disk usage on webserver"*
282
+ > → `ssh_run_command(alias='webserver', command='df -h')`
283
+
284
+ > *"Read the nginx config on the web box"*
285
+ > → `ssh_read_file(alias='webserver', remote_path='/etc/nginx/nginx.conf')`
286
+
287
+ > *"Tail the last 100 lines of syslog on bastion"*
288
+ > → `ssh_run_command(alias='bastion', command='tail -n 100 /var/log/syslog')`
289
+
290
+ > *"Deploy this config file to devbox"*
291
+ > → `ssh_write_file(alias='devbox', remote_path='/etc/myapp/config.yaml', content='...')`
292
+
293
+ > *"Download today's DB backup from webserver"*
294
+ > → `ssh_download_file(alias='webserver', remote_path='/backups/db-today.sql.gz', local_path='/tmp/db-today.sql.gz')`
295
+
296
+ ---
297
+
298
+ ## CLI reference
299
+
300
+ ```
301
+ sshand [subcommand] [options]
302
+
303
+ Subcommands:
304
+ setup Interactive first-run wizard
305
+
306
+ Options:
307
+ --transport {stdio,http} Transport (default: stdio)
308
+ --port INT HTTP port (default: 8000)
309
+ --host STR HTTP bind address (default: 127.0.0.1)
310
+
311
+ Examples:
312
+ sshand # start stdio server
313
+ sshand setup # first-run wizard
314
+ sshand --transport http # start HTTP server on :8000
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Security notes
320
+
321
+ - Keep `hosts.yaml` out of version control if it contains passwords — it is excluded by the included `.gitignore`. Copy `hosts.yaml.example` to `hosts.yaml` to get started.
322
+ - Prefer key-based or agent auth over password auth for any internet-facing host.
323
+ - The HTTP transport binds to `127.0.0.1` by default.
324
+ - When exposing the HTTP server publicly (for Claude.ai / ChatGPT web), use TLS and consider adding authentication via a reverse proxy.
325
+ - `ssh_run_command` is marked `destructiveHint: true` — MCP clients that respect annotations will prompt before running potentially dangerous commands.
326
+
327
+ ---
328
+
329
+ ## Project structure
330
+
331
+ ```
332
+ sshand/
333
+ ├── server.py # FastMCP server — all 11 tools + CLI entry point
334
+ ├── ssh_client.py # Async paramiko wrapper (command exec + SFTP)
335
+ ├── host_config.py # YAML host inventory manager
336
+ ├── setup_wizard.py # Interactive first-run setup wizard
337
+ ├── platform_utils.py # Windows SSH agent helpers
338
+ ├── hosts.yaml.example # Safe template — copy to hosts.yaml and fill in your values
339
+ ├── hosts.yaml # Your SSH targets (gitignored — copy from hosts.yaml.example)
340
+ ├── INTEGRATIONS.md # Guide: Claude.ai and ChatGPT native extensions
341
+ ├── pyproject.toml # Package metadata + pip/uvx install config
342
+ ├── requirements.txt # Plain pip install fallback
343
+ └── README.md
344
+ ```
sshand-0.1.0/README.md ADDED
@@ -0,0 +1,291 @@
1
+ # SSHand
2
+
3
+ An open MCP server that gives **any AI agent** SSH access to remote Linux/Unix machines — shell commands, file read/write, and SFTP transfers.
4
+
5
+ Works with **Claude.ai**, **Claude Desktop**, **ChatGPT**, **Cursor**, **VS Code Copilot**, **OpenAI Agents SDK**, and any other [MCP-compatible client](https://modelcontextprotocol.io/clients).
6
+
7
+ ---
8
+
9
+ ## Quick start
10
+
11
+ ```bash
12
+ # 1. Install
13
+ pip install sshand
14
+
15
+ # 2. Run the interactive setup wizard
16
+ sshand setup
17
+ ```
18
+
19
+ The wizard walks you through adding your first host, testing the connection, and copying the right config snippet for whichever AI client you use.
20
+
21
+ ---
22
+
23
+ ## Installation options
24
+
25
+ ### Option A — pip (recommended for most users)
26
+
27
+ ```bash
28
+ pip install sshand # from PyPI
29
+ pip install -e . # from source, editable install
30
+ ```
31
+
32
+ ### Option B — uvx (zero-install, no venv needed)
33
+
34
+ [uv](https://docs.astral.sh/uv/) is the modern Python package manager. With it installed you can run SSHand without any manual install step:
35
+
36
+ ```bash
37
+ uvx sshand # run server directly
38
+ uvx sshand setup # run setup wizard
39
+ ```
40
+
41
+ This is the cleanest option to recommend to non-technical users.
42
+
43
+ ### Option C — plain Python (no install)
44
+
45
+ ```bash
46
+ git clone https://github.com/YOUR_GITHUB_USERNAME/sshand
47
+ cd sshand
48
+ pip install -r requirements.txt
49
+ python server.py # start server
50
+ python setup_wizard.py # run wizard
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Connecting to your AI client
56
+
57
+ ### Claude.ai and ChatGPT (web + desktop)
58
+
59
+ For Claude.ai web and ChatGPT, SSHand runs as an **HTTP server** and you connect it through each app's native integrations UI.
60
+
61
+ **→ See [INTEGRATIONS.md](INTEGRATIONS.md) for the full step-by-step guide**, including how to expose the server publicly using ngrok or Cloudflare Tunnel, and how to add it to Claude.ai Integrations and ChatGPT Desktop.
62
+
63
+ ---
64
+
65
+ ### Claude Desktop
66
+
67
+ Add to your `claude_desktop_config.json`:
68
+
69
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
70
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "ssh": {
76
+ "command": "uvx",
77
+ "args": ["sshand"],
78
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ Or with plain Python:
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "ssh": {
90
+ "command": "python",
91
+ "args": ["/absolute/path/to/sshand/server.py"],
92
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/sshand/hosts.yaml" }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ Restart Claude Desktop after saving.
99
+
100
+ ---
101
+
102
+ ### Cursor
103
+
104
+ Create or update `.cursor/mcp.json` in your project (or the global Cursor MCP settings):
105
+
106
+ ```json
107
+ {
108
+ "mcpServers": {
109
+ "ssh": {
110
+ "command": "uvx",
111
+ "args": ["sshand"],
112
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ ---
119
+
120
+ ### VS Code (GitHub Copilot Chat)
121
+
122
+ Add to `.vscode/mcp.json` or your workspace `settings.json`:
123
+
124
+ ```json
125
+ {
126
+ "mcp": {
127
+ "servers": {
128
+ "ssh": {
129
+ "type": "stdio",
130
+ "command": "uvx",
131
+ "args": ["sshand"],
132
+ "env": { "SSH_MCP_HOSTS_FILE": "/absolute/path/to/hosts.yaml" }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ---
140
+
141
+ ### OpenAI Agents SDK
142
+
143
+ ```bash
144
+ # Terminal 1 — keep this running
145
+ sshand --transport http --port 8000
146
+ ```
147
+
148
+ ```python
149
+ from agents import Agent
150
+ from agents.mcp import MCPServerStreamableHttp
151
+
152
+ ssh_server = MCPServerStreamableHttp(url="http://localhost:8000/mcp")
153
+ agent = Agent(name="ops-agent", mcp_servers=[ssh_server])
154
+ ```
155
+
156
+ ---
157
+
158
+ ### Any other MCP client (HTTP)
159
+
160
+ ```bash
161
+ sshand --transport http --port 8000
162
+ ```
163
+
164
+ MCP endpoint: `http://localhost:8000/mcp`
165
+
166
+ For remote access, put a reverse proxy (nginx / Caddy) in front with TLS. Never expose port 8000 directly on a public interface.
167
+
168
+ ---
169
+
170
+ ## Host inventory
171
+
172
+ Hosts are stored in `hosts.yaml` (set a different path with the `SSH_MCP_HOSTS_FILE` env var). You can edit the file directly or let your agent call `ssh_add_host`.
173
+
174
+ Copy `hosts.yaml.example` to `hosts.yaml` to get started:
175
+
176
+ ```bash
177
+ cp hosts.yaml.example hosts.yaml
178
+ ```
179
+
180
+ ### Auth types
181
+
182
+ **Key file** — most common, most secure:
183
+ ```yaml
184
+ auth:
185
+ type: key
186
+ key_path: ~/.ssh/id_rsa # ~ is expanded automatically
187
+ passphrase: null # set if the key is encrypted
188
+ ```
189
+
190
+ **Password** — convenient for dev/test, avoid on internet-facing servers:
191
+ ```yaml
192
+ auth:
193
+ type: password
194
+ password: s3cr3t
195
+ ```
196
+
197
+ **SSH agent** — no credentials stored at all, delegates to the running `ssh-agent`:
198
+ ```yaml
199
+ auth:
200
+ type: agent
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Available tools
206
+
207
+ | Tool | Description | Read-only? |
208
+ |------|-------------|------------|
209
+ | `ssh_list_hosts` | List all configured SSH targets | ✅ |
210
+ | `ssh_add_host` | Register a new SSH host | ❌ |
211
+ | `ssh_remove_host` | Remove a host from inventory | ❌ |
212
+ | `ssh_test_connection` | Verify auth works for a host | ✅ |
213
+ | `ssh_run_command` | Execute a shell command + capture output | ❌ |
214
+ | `ssh_read_file` | Read a remote file's contents | ✅ |
215
+ | `ssh_write_file` | Create or overwrite a remote file | ❌ |
216
+ | `ssh_list_directory` | Browse a remote directory | ✅ |
217
+ | `ssh_upload_file` | Push a local file to the remote host (SFTP) | ❌ |
218
+ | `ssh_download_file` | Pull a remote file to this machine (SFTP) | ✅ |
219
+ | `ssh_get_local_info` | Return OS and path style of the MCP server host | ✅ |
220
+
221
+ ---
222
+
223
+ ## Example conversations
224
+
225
+ > *"What servers do you have access to?"*
226
+ > → `ssh_list_hosts`
227
+
228
+ > *"Check disk usage on webserver"*
229
+ > → `ssh_run_command(alias='webserver', command='df -h')`
230
+
231
+ > *"Read the nginx config on the web box"*
232
+ > → `ssh_read_file(alias='webserver', remote_path='/etc/nginx/nginx.conf')`
233
+
234
+ > *"Tail the last 100 lines of syslog on bastion"*
235
+ > → `ssh_run_command(alias='bastion', command='tail -n 100 /var/log/syslog')`
236
+
237
+ > *"Deploy this config file to devbox"*
238
+ > → `ssh_write_file(alias='devbox', remote_path='/etc/myapp/config.yaml', content='...')`
239
+
240
+ > *"Download today's DB backup from webserver"*
241
+ > → `ssh_download_file(alias='webserver', remote_path='/backups/db-today.sql.gz', local_path='/tmp/db-today.sql.gz')`
242
+
243
+ ---
244
+
245
+ ## CLI reference
246
+
247
+ ```
248
+ sshand [subcommand] [options]
249
+
250
+ Subcommands:
251
+ setup Interactive first-run wizard
252
+
253
+ Options:
254
+ --transport {stdio,http} Transport (default: stdio)
255
+ --port INT HTTP port (default: 8000)
256
+ --host STR HTTP bind address (default: 127.0.0.1)
257
+
258
+ Examples:
259
+ sshand # start stdio server
260
+ sshand setup # first-run wizard
261
+ sshand --transport http # start HTTP server on :8000
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Security notes
267
+
268
+ - Keep `hosts.yaml` out of version control if it contains passwords — it is excluded by the included `.gitignore`. Copy `hosts.yaml.example` to `hosts.yaml` to get started.
269
+ - Prefer key-based or agent auth over password auth for any internet-facing host.
270
+ - The HTTP transport binds to `127.0.0.1` by default.
271
+ - When exposing the HTTP server publicly (for Claude.ai / ChatGPT web), use TLS and consider adding authentication via a reverse proxy.
272
+ - `ssh_run_command` is marked `destructiveHint: true` — MCP clients that respect annotations will prompt before running potentially dangerous commands.
273
+
274
+ ---
275
+
276
+ ## Project structure
277
+
278
+ ```
279
+ sshand/
280
+ ├── server.py # FastMCP server — all 11 tools + CLI entry point
281
+ ├── ssh_client.py # Async paramiko wrapper (command exec + SFTP)
282
+ ├── host_config.py # YAML host inventory manager
283
+ ├── setup_wizard.py # Interactive first-run setup wizard
284
+ ├── platform_utils.py # Windows SSH agent helpers
285
+ ├── hosts.yaml.example # Safe template — copy to hosts.yaml and fill in your values
286
+ ├── hosts.yaml # Your SSH targets (gitignored — copy from hosts.yaml.example)
287
+ ├── INTEGRATIONS.md # Guide: Claude.ai and ChatGPT native extensions
288
+ ├── pyproject.toml # Package metadata + pip/uvx install config
289
+ ├── requirements.txt # Plain pip install fallback
290
+ └── README.md
291
+ ```