Skip to main content
Glama
xtawa

mcp_ssh_connectors

by xtawa

mcp_ssh_connectors

A host-side MCP server and local terminal tool that let an AI use the host machine's OpenSSH client to reach any SSH server with a request-scoped password or private key, even when the model sandbox has no direct network path. Configured named targets remain available for compatibility.

通过宿主机的 OpenSSH 客户端,让 AI 使用请求中提供的密码或私钥连接任意 SSH 服务器;支持本地 stdio,也支持带 API Key 鉴权的 Streamable HTTP MCP。

Dynamic MCP connections can execute any validated single-line command. HTTP clients still need a scoped, unexpired Bearer API key. Credentials are request-scoped and are never logged or returned.

Architecture

flowchart LR
  AI[AI / MCP client] -->|stdio, local OS boundary| S[mcp-ssh-server]
  AI -->|HTTP + Bearer API key| H[mcp-ssh-http]
  H --> K[scrypt key store + scopes]
  S --> P[dynamic connection or configured target]
  H --> P
  U[Human terminal] -->|mcp-ssh CLI| P
  P -->|spawn, shell=false| O[Host OpenSSH client]
  O --> R[configured SSH instances]
  P --> A[JSONL audit log]

Node.js 20+ and an OpenSSH-compatible ssh executable are required.

Related MCP server: ssh-mcp-server

Included

  • MCP tools: ssh_list_targets, ssh_preview, ssh_check, ssh_exec; check/exec accept configured targets or arbitrary dynamic connections

  • Local stdio MCP and authenticated Streamable HTTP MCP

  • API key creation, listing, expiry, target scopes, operation scopes, and revocation

  • Local CLI: init, targets, preview, check, exec, connect, mcp, http, key

  • TOFU host-key checking for dynamic servers, request-scoped credentials, timeouts, output caps, and JSONL auditing

  • ProxyJump, identity-file, port, and dedicated known-hosts support

  • CI and unit tests

Install

git clone https://github.com/xtawa/mcp_ssh_connectors.git
cd mcp_ssh_connectors
npm install
npm run check
npm link
mcp-ssh init
$EDITOR ~/.config/mcp-ssh/config.json

After adding an optional configured target, it can still be tested through the CLI:

ssh example
mcp-ssh preview example -- uname -a
mcp-ssh check example
mcp-ssh exec example -- uname -a

Dynamic SSH connections

ssh_check and ssh_exec accept a connection object instead of a configured target. The connection requires a host, username, optional port, and exactly one authentication method.

Password example:

{
  "connection": {
    "host": "203.0.113.10",
    "username": "deploy",
    "port": 22,
    "authentication": {
      "type": "password",
      "password": "request-scoped-password"
    }
  },
  "command": "uname -a",
  "reason": "diagnostics"
}

Private-key example:

{
  "connection": {
    "host": "server.example.com",
    "username": "root",
    "authentication": {
      "type": "privateKey",
      "privateKey": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----",
      "passphrase": "optional-key-passphrase"
    }
  },
  "command": "systemctl status example"
}

Dynamic commands are not checked against configured allow/deny expressions. They must be non-empty, single-line, NUL-free, and within policy.maxCommandLength. Dynamic calls use -F none, so local/system SSH configuration cannot inject a proxy or other options. New host keys use StrictHostKeyChecking=accept-new: the first key is recorded, while later key changes are rejected.

Passwords and key passphrases are supplied to OpenSSH through a forced SSH_ASKPASS helper. Private-key content is written to a per-request 0600 temporary file; Windows also receives an explicit user-only ACL. Temporary credential files are removed when the request finishes. Credentials are not included in process arguments, audit records, tool results, or error objects.

Local stdio MCP

{
  "mcpServers": {
    "ssh-connectors": {
      "command": "mcp-ssh-server",
      "env": { "MCP_SSH_CONFIG": "/absolute/path/to/config.json" }
    }
  }
}

Stdio relies on the local OS account boundary; no API key is sent through the model context.

HTTP MCP with API Key authentication

Create a read-only key restricted to staging:

mcp-ssh key create staging-observer \
  --scopes mcp,ssh:read \
  --expires 30d

Create an execution key for two targets:

mcp-ssh key create deploy-agent \
  --scopes mcp,ssh:read,ssh:exec \
  --expires 7d

The complete token is shown once. The key store contains only its salted scrypt hash. List metadata or revoke a key:

mcp-ssh key list
mcp-ssh key revoke KEY_ID

Start the authenticated endpoint:

mcp-ssh http
# or: mcp-ssh-http
# http://127.0.0.1:3000/mcp

Clients send:

Authorization: Bearer mcp_ssh.KEY_ID.SECRET

Example MCP client configuration:

{
  "mcpServers": {
    "ssh-connectors-http": {
      "url": "http://127.0.0.1:3000/mcp",
      "headers": { "Authorization": "Bearer ${MCP_SSH_API_KEY}" }
    }
  }
}

Keep the token in the client environment or secret manager. Do not commit it. For any non-loopback deployment, use TLS and set http.allowedHosts; preferably place the service behind a hardened reverse proxy.

Scopes

Scope

Permission

mcp

Required to reach the MCP endpoint

ssh:read

List targets, preview commands, and check connectivity

ssh:exec

Execute commands that also pass host policy

New API keys default to target *, which permits their SSH operation scopes to use dynamic connections. --targets remains available to restrict access to legacy configured targets; it does not restrict dynamic hosts.

Configuration

{
  "version": 1,
  "sshBinary": "ssh",
  "auth": { "keyStore": "~/.config/mcp-ssh/keys.json" },
  "http": {
    "host": "127.0.0.1",
    "port": 3000,
    "allowedHosts": [],
    "allowedOrigins": []
  },
  "audit": { "required": true, "logCommands": false },
  "defaults": {
    "timeoutMs": 30000,
    "connectTimeoutSeconds": 10,
    "maxOutputBytes": 1048576,
    "knownHostsFile": "~/.ssh/known_hosts"
  },
  "policy": {
    "maxCommandLength": 4096,
    "deniedCommands": ["(?:^|\\s)sudo(?:\\s|$)"]
  },
  "targets": {
    "staging": {
      "destination": "deploy@10.0.20.15",
      "identityFile": "~/.ssh/staging_ed25519",
      "proxyJump": "bastion",
      "tags": ["staging", "linux"],
      "allowedCommands": [
        "^uname -a$",
        "^systemctl status [A-Za-z0-9_.@-]+$"
      ],
      "deniedCommands": ["(?:^|[;&|]\\s*)rm(?:\\s|$)"],
      "requireReason": true
    }
  }
}

The targets object is optional and may be empty. For configured targets, deny rules run before allow rules and a target with no allowedCommands is blocked. Dynamic connections bypass these configured command expressions and retain only the global length and single-line validation.

Terminal commands

mcp-ssh init [--config PATH]
mcp-ssh targets [--config PATH]
mcp-ssh preview TARGET [--reason TEXT] -- COMMAND
mcp-ssh check TARGET [--config PATH]
mcp-ssh exec TARGET [--reason TEXT] -- COMMAND
mcp-ssh connect TARGET [--config PATH]
mcp-ssh mcp [--config PATH]
mcp-ssh http [--host HOST] [--port PORT] [--config PATH]
mcp-ssh key create NAME [--targets LIST] [--scopes LIST] [--expires 30d]
mcp-ssh key list [--config PATH]
mcp-ssh key revoke KEY_ID [--config PATH]

connect is a human-only interactive shell and is not exposed as an MCP tool.

Request authorization order

For HTTP requests the connector applies four independent checks:

  1. validate the Bearer key hash, expiry, and revocation state;

  2. require operation scope (ssh:read or ssh:exec), plus target access only for a configured target;

  3. validate dynamic single-line commands, or apply configured-target deny/allow rules;

  4. authenticate to the remote machine with the request password/private key or configured host SSH identity.

The API key id is recorded as the audit actor. Neither bearer tokens nor SSH key contents are logged.

Security

Read docs/security.md before exposing this server. Dynamic access deliberately gives an ssh:exec caller broad reach. Plain HTTP should stay on loopback or inside a trusted tunnel. Non-loopback deployments need TLS, explicit host/origin policy, short-lived scoped keys, and append-only audit storage.

Ideas and next steps

See docs/roadmap.md for human approvals, external identity providers, ephemeral SSH certificates, constrained SFTP, fleet blast-radius budgets, cached host facts, telemetry, and session recording.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    B
    quality
    F
    maintenance
    An MCP server that allows AI models to execute system commands on local machines or remote hosts via SSH, supporting persistent sessions and environment variables.
    1
    38
    27
    MIT
  • A
    license
    -
    quality
    D
    maintenance
    An MCP server that enables remote SSH command execution and bidirectional file transfers through a standardized interface. It allows AI assistants to securely manage remote servers while keeping credentials isolated and applying command-level security controls.
    ISC
  • A
    license
    -
    quality
    D
    maintenance
    An MCP server that gives AI assistants full SSH/SFTP remote operations — session management, command execution, interactive shells, file transfers, port forwarding, and system diagnostics.
    2
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that gives AI agents SSH access to remote machines through your local OpenSSH client, enabling remote command execution, file transfer, persistent shell sessions, and port forwarding.
    17
    5
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Operate your Linux servers from your LLM. Every action runs through an auditable allowlist.

View all MCP Connectors

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/xtawa/mcp_ssh_connectors'

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