Skip to content

Windows Support

Overview

cygnus-ssh-mcp supports Windows Server as a target system via SSH. This document covers supported versions, requirements, and behavioral differences from Linux/macOS.

Supported Windows Versions

Windows Version PowerShell Status
Windows Server 2022 5.1 Fully supported
Windows Server 2019 5.1 Fully supported
Windows Server 2016 5.0 Fully supported
Windows 11 5.1 Fully supported
Windows 10 5.0+ Fully supported
Windows Server 2012 R2 4.0 Not supported (requires WMF 5.1)
Windows 8.1 and earlier < 5.0 Not supported

Why PowerShell 5.0+?

The following PowerShell features require version 5.0 or later:

Feature Cmdlet Used For
Archive operations Compress-Archive, Expand-Archive Creating/extracting archives
Depth-limited listing Get-ChildItem -Depth Directory listings with max depth

Connecting to a Windows system with PowerShell < 5.0 will result in an error:

PowerShell 4.x detected. This tool requires PowerShell 5.0 or later.
Windows Server 2016+, Windows 10+ have PowerShell 5.0+ built-in.
For older Windows versions, install Windows Management Framework (WMF) 5.1.

Prerequisites

1. OpenSSH Server

Windows Server 2019+ includes OpenSSH as an optional feature. To enable:

# Check if installed
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*'

# Install OpenSSH Server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# Start and enable the service
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

# Confirm firewall rule exists
Get-NetFirewallRule -Name *ssh*

For Windows Server 2016, download OpenSSH from Microsoft's GitHub releases.

2. Administrator Access

Unlike Linux where sudo elevates privileges per-command, Windows elevation works differently:

  • Elevated session: Connect as a user in the Administrators group
  • Non-elevated session: Limited to user-level operations

The use_sudo parameter on tools is ignored on Windows. If an operation requires admin rights, the SSH session must be connected as an Administrator.

Behavioral Differences

Path Separators

Platform Separator Example
Linux/macOS / /home/user/file.txt
Windows \ C:\Users\user\file.txt

Tools accept Windows-style paths:

ssh_file_write with file_path: "C:\Users\admin\config.txt"
ssh_dir_list_advanced with path: "C:\Program Files"

Archive Format

Platform Default Format
Linux/macOS .tar.gz
Windows .zip

The ssh_archive_create tool creates .zip files on Windows using Compress-Archive.

Permissions Model

Aspect Linux/macOS Windows
Permission format Octal (755, 644) ACLs
Owner/Group UID/GID SID-based
Elevation sudo per command Session-level

The ssh_file_stat tool returns owner information but not Unix-style permission bits on Windows.

Line Endings

Windows uses \r\n (CRLF) line endings. The tools handle this automatically: - File writes preserve the content as-is - File reads may include \r\n in output

Temp Directory

Platform Default Temp Path
Linux /tmp
macOS /tmp or /var/folders/...
Windows C:\Users\<user>\AppData\Local\Temp

Tool-Specific Notes

Command Execution (ssh_cmd_run)

Commands run with cmd.exe semantics by default - the same as typing them at a cmd.exe prompt - regardless of the SSH server's configured DefaultShell. There's no need to manually prefix commands with cmd /c or powershell -Command "..."; ssh_cmd_run always spawns the command through an internal wrapper that handles this consistently:

ssh_cmd_run with command: "dir C:\Windows"

For PowerShell-specific syntax (cmdlets, pipelines using PowerShell semantics), invoke powershell -Command "..." explicitly yourself, same as you would at a cmd.exe prompt:

ssh_cmd_run with command: "powershell -Command \"Get-Process | Sort-Object CPU -Descending | Select-Object -First 5\""

The wrapper captures a real remote process ID (not a local placeholder), so runtime_timeout and ssh_cmd_kill correctly target the actual process. It also recovers the real exit code via an internal marker mechanism rather than trusting the SSH channel's own exit status - a plain SSH exec channel through cmd.exe silently reports the wrong exit code (a known Win32-OpenSSH/cmd.exe interaction) whenever a nested child process is involved, which is exactly what running a command this way requires; commands that fail now correctly report their real exit code instead of a generic 1.

Directory Operations

Operation Linux Windows
List files find Get-ChildItem
Directory size du -sb Measure-Object -Sum Length
Search content grep -r Select-String -Recurse

File Operations

Operation Linux Windows
Find pattern grep Select-String
File stats stat Get-Item, Get-Acl
Copy file cp Copy-Item
Move file mv Move-Item

Background Tasks

Aspect Linux Windows
Launch method nohup cmd & WMI (Invoke-CimMethod -ClassName Win32_Process -MethodName Create)
Check running kill -0 $pid Get-Process -Id $pid
Terminate kill -15 / kill -9 taskkill /F /T (kills the whole process tree)

Windows background tasks are launched via WMI rather than Start-Process: a Start-Process-launched child inherits membership in the SSH session's Windows Job Object, and gets killed the instant that session ends, regardless of any "detached"/hidden-window flags. WMI process creation goes through a separate service process, so the task genuinely survives independently until it finishes or is explicitly killed. Termination uses taskkill /F /T (not Stop-Process) because every task PID is a cmd.exe/powershell.exe wrapper, not the real workload - Stop-Process on just the wrapper orphans the actual process; /T kills the whole tree in one call.

System Information (ssh_conn_host_info)

Windows system info is gathered via CIM/WMI:

Info Linux Source Windows Source
CPU /proc/cpuinfo Win32_Processor
Memory free -m Win32_OperatingSystem
OS version /etc/os-release Win32_OperatingSystem
Disk df -h Win32_LogicalDisk
Network ip addr Get-NetIPAddress

Known Limitations

1. Unicode in Command Output

Issue: PowerShell over SSH doesn't properly encode UTF-8 output. Emojis and special characters may appear as ? or garbled text. This is a fundamental Windows console encoding limitation—PowerShell uses the system's OEM code page (typically CP437 or CP1252) for stdout, not UTF-8.

Affected: Reading files via ssh_cmd_run with PowerShell commands like Get-Content.

Not affected: SFTP-based operations bypass the console entirely and work correctly with Unicode.

Solution: Use ssh_file_read to read file contents. This tool uses SFTP to transfer raw bytes and decodes them on the client side, completely avoiding the Windows console encoding problem. Works correctly with emojis, international characters, and any valid UTF-8 content.

2. No Per-Command Elevation

Issue: Windows doesn't have sudo. The use_sudo parameter is ignored.

Workaround: Connect as an Administrator user for operations requiring elevation.

3. Non-Empty Directory Removal

Behavior: When ssh_dir_remove is called with recursive=False on a non-empty directory, Windows will return an error immediately (same as Linux).

4. Local PowerShell Falling Back to a Local ssh Call

Issue: If you (or an LLM agent) run this server's ssh_cmd_run-equivalent shell command from a local Windows PowerShell prompt rather than through the MCP tool - e.g. shelling out to ssh user@host "some | command with | pipes" directly from PowerShell - PowerShell parses pipe/redirect characters in the command string before they ever reach the remote shell. This can silently split or reinterpret a command that was meant to run as one pipeline entirely on the remote host (e.g. apt|dpkg patterns).

Not an issue for: Commands sent through the MCP ssh_cmd_run tool itself - those go through paramiko's exec_command, not a local shell, so this doesn't apply.

Workaround: If constructing a local ssh ... command by hand in PowerShell, quote the entire remote command as a single string and be aware PowerShell's own parsing happens first.

Host Configuration Example

# Windows Server with password auth
["administrator@winserver.example.com"]
password = "SecurePassword123"
port = 22
alias = "win-prod"
description = "Windows production server"

# Windows with SSH key
["deploy@winserver.example.com"]
keyfile = "~/.ssh/id_ed25519"
port = 22
alias = "win-staging"
description = "Windows staging server"

Note: sudo_password is not used for Windows connections.

Troubleshooting

Connection Refused

Ensure OpenSSH Server is running:

Get-Service sshd
Start-Service sshd

Permission Denied

Verify the user is in the Administrators group for admin operations:

net localgroup Administrators

PowerShell Version Error

Check PowerShell version:

$PSVersionTable.PSVersion

If below 5.0, install WMF 5.1.

Commands Not Found

Ensure PowerShell is the default shell for SSH. Check C:\ProgramData\ssh\sshd_config:

# Should NOT have this line, or it should point to PowerShell:
# Subsystem powershell C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe