mcp_ssh_connectors

mcp_ssh_connectors

An MCP server that enables AI to execute SSH commands on remote servers using the host's OpenSSH client, supporting both configured targets and dynamic connections with request-scoped credentials.

Category
访问服务器

README

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.

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.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选