Skip to content

feat: add ProxyCommand support for SOCKS5 and custom proxy connections#24

Open
majordave wants to merge 2 commits intobvisible:mainfrom
majordave:feat/proxycommand
Open

feat: add ProxyCommand support for SOCKS5 and custom proxy connections#24
majordave wants to merge 2 commits intobvisible:mainfrom
majordave:feat/proxycommand

Conversation

@majordave
Copy link
Copy Markdown

Summary

Adds SSH ProxyCommand support to MCP SSH Manager alongside existing ProxyJump functionality. This enables connections through:

  • SOCKS5 proxies (e.g., ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p)
  • Custom proxy commands (e.g., ssh -W %h:%p bastion)
  • Windows SSH proxy commands

Changes

  1. src/index.js - Added createProxyCommandSocket() function (lines 389-432) to execute proxy commands and create socket connections
  2. src/config-loader.js - Added proxyCommand parsing for both TOML (proxy_command) and .env (SSH_SERVER_*_PROXYCOMMAND) formats
  3. Documentation - Updated README.md and CLAUDE.md with ProxyCommand examples and configuration
  4. Version bump - Updated package.json from 3.2.2 → 3.3.0

Features

  • SOCKS5 Proxy Support: Connect through SOCKS5 proxies for servers behind firewalls
  • Custom Proxy Commands: Support for any command that reads stdin/writes stdout with %h/%p placeholders
  • Windows Compatibility: Works with Windows SSH proxy commands (e.g., C:\Windows\System32\OpenSSH\ssh.exe -W %h:%p user@host)
  • Error Handling: Proper timeout management and child process cleanup
  • Backward Compatible: Existing ProxyJump functionality unchanged

Testing

The implementation has been tested with:

  • ✅ SOCKS5 proxy configurations (ncat with local proxy)
  • ✅ Windows SSH proxy commands (ssh.exe -W flag)
  • ✅ Existing ProxyJump connections continue to work
  • ⚠️ Various network conditions (timeouts handled gracefully)

All proxy command executions follow the same security model as existing SSH connections.

Configuration Examples

.env format:

SSH_SERVER_SOCKS_HOST=target.example.com
SSH_SERVER_SOCKS_USER=admin
SSH_SERVER_SOCKS_PROXYCOMMAND="ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p"

TOML format:

[ssh_servers.socks]
host = "target.example.com"
user = "admin"
proxy_command = "ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p"

Why This Matters

Many corporate environments require proxy connections for SSH access. While ProxyJump handles bastion hosts, ProxyCommand is essential for:

  • SOCKS5 proxies (common in VPN setups)
  • Custom tunneling solutions
  • Windows environments using native SSH
  • Legacy proxy configurations

This completes the SSH proxy support alongside the existing ProxyJump feature.

References

Follows the contribution pattern from: 423857d

Adds SSH ProxyCommand support to MCP SSH Manager alongside existing
ProxyJump functionality. Supports SOCKS5 proxies, custom proxy commands,
and Windows SSH proxy commands with proper error handling and cleanup.

Configuration formats:
- .env: SSH_SERVER_*_PROXYCOMMAND
- TOML: proxy_command field

Examples use generic placeholders (user@jump-host) for documentation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@majordave majordave closed this Apr 18, 2026
@majordave majordave reopened this Apr 18, 2026
…arsing

- Reconvert CLAUDE.md from CRLF to LF and restore trailing newline so the
  diff only shows the 4 intentional lines (not the full 212-line rewrite)
- Replace naive whitespace split of the proxy command with spawn({ shell: true }),
  matching OpenSSH ProxyCommand semantics so quoted args, pipes and shell
  metacharacters work as users expect
- Forward proxy stderr to the MCP server's stderr for debugging
- Guard resolve/reject against double-settle on exit after successful spawn
- Include proxyCommand presence in the connection log
@bvisible
Copy link
Copy Markdown
Owner

Thanks for the PR! I pushed a follow-up commit (7f91e58) addressing two points that came up during review:

1. CLAUDE.md diff noise
The file had been re-saved with CRLF line endings and no trailing newline, which made every one of its 212 lines show up as changed. I converted it back to LF + trailing newline so the diff now only shows the 4 lines you actually intended to add (the PROXYCOMMAND / proxy_command entries and the Key Implementation Details bullet).

2. Proxy command argument parsing
The original cmd.split(/\s+/) would break on any quoted argument containing spaces, e.g. ssh -o "UserKnownHostsFile=/dev/null" -W %h:%p user@host. I replaced it with spawn(cmd, { shell: true }), which matches OpenSSH's ProxyCommand semantics — the command is handed to /bin/sh -c (or cmd.exe on Windows), so quotes, pipes, env expansion, and shell metacharacters all work as users expect.

Also included in the same commit:

  • Proxy stderr is now forwarded to the MCP server's stderr, which makes debugging ncat/ssh proxy failures much easier.
  • Added a settled guard so a non-zero exit arriving after a successful spawn can't double-reject the promise.
  • logger.logConnection now records whether a proxyCommand was used.

Local testing I ran:

  • ./scripts/validate.sh — all checks pass (JS/Python syntax, MCP startup, etc.).
  • An end-to-end test against a local TCP echo server using the createProxyCommandSocket code path, covering: simple command, quoted args with spaces (sh -c "nc %h %p"), shell piping (nc %h %p | cat), and a failing binary. All four behave correctly — byte round-trip works and failures surface cleanly via the socket's error event.
  • A ConfigLoader test covering .env parsing, TOML parsing, and the exportToEnv / exportToToml round-trip for the new proxyCommand field.

I don't have a live SOCKS5 proxy to point at a real server, so could you re-run your SOCKS5 / Windows ssh.exe -W scenarios against this branch and confirm the proxy still connects end-to-end? Once you give the thumbs up we're good to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants