Skip to main content
Glama

What Is This?

SSH MCP Server lets you manage remote Linux servers through natural language in VS Code Copilot Chat. Instead of switching to a terminal and remembering SSH commands, you just ask:

"Check disk usage on production-web"

"Show me the last 200 lines of /var/log/nginx/error.log on staging"

"Download /var/log/syslog from web-server-01 for incident INC-2026-0309"

The server enforces strict security policies — no raw shell access, all commands go through pre-approved templates, parameters are regex-validated, secrets in output are auto-redacted, and privileged operations require an approval workflow.

Features

  • 23 MCP tools — host discovery, session management, command execution (sync + background), file transfer, SFTP operations, SSH key management, certificate lifecycle, approval workflows

  • Template-only execution — no raw shell; every command matches a registered template with regex-validated parameters

  • 3-tier security model — read-only (Tier 0), controlled mutation with confirmation (Tier 1), privileged with approval workflow (Tier 2)

  • Automatic secret redaction — AWS keys, bearer tokens, passwords, private keys are scrubbed from output

  • Tamper-evident audit log — every operation is logged with hash-chain integrity verification

  • Short-lived SSH certificates — issue and revoke certificates with TTL enforcement via a local CA

  • Persistent SSH sessions — connection pooling with keepalive probes and configurable idle timeout

  • Background command execution — run long-running template commands asynchronously with output polling

  • Path traversal protection.. sequences blocked in all path parameters and file transfers

  • Transfer policy — allowed paths, blocked extensions, size limits, mandatory justification for downloads

Quick Start

Prerequisites

  • Python 3.11+

  • VS Code with GitHub Copilot extension

  • SSH access to at least one remote Linux host


Install

As vscode plugin

https://marketplace.visualstudio.com/items?itemName=bhayanak.ssh-mcp-server-secure

Python package: https://pypi.org/project/ssh-mcp-server-copilot/


Install from Source (for development / contributing)

git clone https://github.com/bhayanak/ssh-mcp-server.git
cd ssh-mcp-server

python -m venv .venv
source .venv/bin/activate   # macOS/Linux
# .venv\Scripts\activate    # Windows

pip install -e ".[dev]"

For local development, create .vscode/mcp.json pointing to the local source:

{
  "servers": {
    "ssh-mcp": {
      "type": "stdio",
      "command": "${workspaceFolder}/.venv/bin/python",
      "args": ["-m", "ssh_mcp.server"],
      "env": {
        "SSH_MCP_CONFIG_DIR": "${workspaceFolder}/config",
        "SSH_MCP_HOSTS_FILE": "${workspaceFolder}/config/hosts.json",
        "SSH_MCP_TEMPLATES_FILE": "${workspaceFolder}/config/templates.json",
        "SSH_MCP_AUDIT_LOG_DIR": "${workspaceFolder}/audit_logs",
        "SSH_MCP_CERT_DATA_DIR": "${workspaceFolder}/cert_data",
        "SSH_MCP_APPROVAL_DATA_DIR": "${workspaceFolder}/approval_data",
        "SSH_MCP_SSH_KNOWN_HOSTS_FILE": "~/.ssh/known_hosts"
      }
    }
  }
}

Configure Your Hosts

Edit the hosts file with your actual servers. If you used ssh-mcp-server-copilot init, edit ~/.ssh-mcp/hosts.json. If developing from source, edit config/hosts.json.

[
  {
    "host_id": "my-server",
    "hostname": "192.168.1.10",
    "port": 22,
    "ssh_user": "deploy",
    "labels": {"env": "production", "role": "web"},
    "description": "Production web server",
    "allowed_roles": ["operator", "admin"]
  }
]

Field

Required

Description

host_id

Yes

Unique identifier (alphanumeric, dots, dashes)

hostname

Yes

IP address or FQDN

port

No

SSH port (default: 22)

ssh_user

Yes*

Remote SSH username. If empty, uses your OS username

labels

No

Key-value tags for organization

description

No

Human-readable description

allowed_roles

No

Which roles can access this host (default: operator, admin)

Set Up SSH Access

Your SSH key must be authorized on each host:

# Generate a key if you don't have one
ssh-keygen -t ed25519 -C "your-email@example.com"

# Copy to each host
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@192.168.1.10

# Load into ssh-agent (required — the MCP server uses the agent)
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Verify access
ssh deploy@192.168.1.10 "echo OK"

Add host keys to known_hosts:

ssh-keyscan -H 192.168.1.10 >> ~/.ssh/known_hosts

Start Using

  1. Open the workspace in VS Code

  2. The MCP server auto-starts from .vscode/mcp.json

  3. Open Copilot Chat (Cmd+Shift+I / Ctrl+Shift+I)

  4. Switch to "Agent" mode (critical — only Agent mode can invoke MCP tools)

  5. Verify tools are loaded — click the tools icon in the chat input bar, you should see 23 tools from ssh-mcp

Now just ask in natural language:

> List all my SSH hosts
> Check disk usage on my-server
> Show me the last 100 lines of /var/log/syslog on my-server
> What's the status of nginx on my-server?

Tools (23)

Tier 0 — Read-Only (No Confirmation)

Tool

Description

list_hosts

List all configured SSH hosts with labels and metadata

get_host_facts

Get OS, uptime, kernel info from a host

get_audit_logs

View the tamper-evident audit trail

list_templates

List available command templates

list_pending_approvals

View pending approval requests

Session Management

Tool

Description

ssh_connect

Open a persistent SSH session (returns session_id for reuse)

ssh_disconnect

Close a persistent session

ssh_list_sessions

List active sessions and remaining connection slots

ssh_session_ping

Health-check a session (liveness, idle time, uptime)

Tier 1 — Controlled Mutation (Confirmation Required)

Tool

Description

run_ssh_command

Execute a template command on a host (supports session_id for persistent connections)

transfer_file

Download/upload files via SFTP with path and extension policies (supports session_id)

Background Command Execution

Tool

Description

run_ssh_command_background

Start a template command in the background (returns job_id)

poll_background_job

Read accumulated stdout/stderr of a background job (redacted)

list_background_jobs

List all background jobs (running + completed)

cancel_background_job

Cancel a running background job

Enhanced SFTP

Tool

Description

sftp_list_directory

List files in a remote directory (within allowed paths)

sftp_delete

Delete a remote file (within allowed paths, requires justification)

Tier 2 — Privileged (Approval Required)

Tool

Description

add_ssh_key

Register a public SSH key with TTL enforcement

remove_ssh_key

Revoke a registered SSH key

issue_cert

Issue a short-lived SSH certificate via the local CA

revoke_cert

Revoke a certificate and delete its PEM

request_approval / approve_request

Approval workflow for privileged ops

Configuration

Command Templates

Templates define which commands can be executed. Edit config/templates.json:

[
  {
    "template_id": "disk_usage",
    "description": "Show disk usage summary",
    "command": "df -h",
    "allowed_params": {},
    "allowed_roles": ["developer", "operator", "admin"],
    "timeout_seconds": 10,
    "risk_level": "low"
  },
  {
    "template_id": "tail_log",
    "description": "Tail the last N lines of a log file",
    "command": "tail -n {lines} {log_path}",
    "allowed_params": {
      "lines": "^[0-9]{1,5}$",
      "log_path": "^/var/log/[a-zA-Z0-9_./-]+$"
    },
    "allowed_roles": ["operator", "admin"],
    "timeout_seconds": 15,
    "risk_level": "low"
  }
]

Each parameter is validated against a regex pattern before substitution. Path traversal (..) is blocked automatically.

Environment Variables

All configuration is via environment variables with the SSH_MCP_ prefix:

Variable

Default

Description

SSH_MCP_CONFIG_DIR

~/.ssh-mcp

Base config directory (all other paths derive from this)

SSH_MCP_HOSTS_FILE

{config_dir}/hosts.json

Path to hosts configuration

SSH_MCP_TEMPLATES_FILE

{config_dir}/templates.json

Path to command templates

SSH_MCP_AUDIT_LOG_DIR

{config_dir}/audit_logs

Audit log directory

SSH_MCP_CERT_DATA_DIR

{config_dir}/cert_data

Certificate storage directory

SSH_MCP_APPROVAL_DATA_DIR

{config_dir}/approval_data

Approval data directory

SSH_MCP_MAX_SESSIONS

10

Max simultaneous SSH sessions

SSH_MCP_SESSION_IDLE_TIMEOUT

300

Idle session timeout (seconds)

SSH_MCP_KEEPALIVE_INTERVAL

15

SSH keepalive interval (seconds)

SSH_MCP_KEEPALIVE_COUNT_MAX

3

Max failed keepalive probes before disconnect

SSH_MCP_MAX_BACKGROUND_JOBS

10

Max concurrent background jobs

SSH_MCP_JOB_OUTPUT_MAX_BYTES

1048576

Max output buffer per background job (1 MB)

SSH_MCP_JOB_TTL_SECONDS

3600

Background job auto-expiry (1 hour)

SSH_MCP_SSH_KNOWN_HOSTS_FILE

(none)

Path to SSH known_hosts file

SSH_MCP_REQUIRE_TWO_PARTY_APPROVAL

true

Require different user as approver

SSH_MCP_AUTH_TOKEN

(none)

Bearer token (empty = dev mode)

SSH_MCP_SSH_TIMEOUT_SECONDS

30

SSH connection timeout

Transfer Policy (Defaults)

Setting

Default

Allowed paths

/tmp/*, /var/log/*

Blocked extensions

.exe, .sh, .bat, .ps1, .dll, .so

Max file size

50 MB

Require justification for downloads

Yes

Roles

Role

Access

developer

Read-only tools, low-risk commands

operator

All Tier 0 + Tier 1 tools

admin

All tools including Tier 2 (key/cert management)

auditor

Audit log access

Security

Design Principles

  1. No raw shell — all commands go through registered templates

  2. Parameter validation — every parameter is regex-validated before substitution

  3. Path traversal blocking.. sequences rejected in all parameters and file paths

  4. Secret redaction — AWS keys, bearer tokens, passwords, private keys automatically scrubbed from output

  5. Approval workflow — privileged operations (key/cert management) require explicit approval with HMAC-verified tokens

  6. Tamper-evident audit — hash-chained audit log for forensic analysis

  7. Strict host validation — paramiko RejectPolicy by default (no auto-accepting unknown hosts)

  8. TTL enforcement — SSH certificates and keys have configurable maximum lifetimes

Approval Workflow

Tier 2 operations follow a 3-step flow:

1. request_approval  →  returns request_id + one-time approval_token
2. approve_request   →  verifies HMAC token, marks approved
3. call the tool     →  pass approval_request_id, consumed after use

With REQUIRE_TWO_PARTY_APPROVAL=true (production), a different user must approve.

Audit Log Verification

python -c "
from ssh_mcp.audit import AuditLogger
from pathlib import Path
logger = AuditLogger(Path('audit_logs'))
ok, msg = logger.verify_chain()
print(f'Chain integrity: {ok} — {msg}')
"

Testing

Unit Tests

# Run all tests
pytest tests/ -v

# With coverage
pytest tests/ -v --cov=ssh_mcp

Runtime Directories (git-ignored, auto-created)

Directory

Purpose

audit_logs/

Tamper-evident audit log (audit.jsonl)

cert_data/

CA keys, issued certificates, revocation list

approval_data/

Pending and consumed approval requests

CLI Reference

ssh-mcp-server-copilot --version          # Print version
ssh-mcp-server-copilot init               # Create ~/.ssh-mcp with default configs
ssh-mcp-server-copilot                    # Start MCP server (stdio transport)
ssh-mcp-server-copilot --config-dir PATH  # Use custom config directory
ssh-mcp-server-copilot --config-dir PATH init  # Init a custom config directory

Contributing

  1. Fork the repository

  2. Create a feature branch: git checkout -b feature/my-feature

  3. Make your changes

  4. Run tests: pytest tests/ -v

  5. Lint: ruff check src/ tests/

  6. Submit a pull request

License

MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bhayanak/ssh-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server