hardened-ssh-mcp

hardened-ssh-mcp

A single-purpose MCP server that lets an AI assistant run commands over SSH on a fixed, pre-configured host only, with an explicit per-call confirmation gate before execution.

Category
访问服务器

README

hardened-ssh-mcp

A single-purpose MCP server that gives an AI assistant (Claude, or any other MCP-compatible client) the ability to run commands over SSH on one pre-configured host, and only that host - with an explicit per-call confirmation gate before anything actually executes.

This started as a fork of a general-purpose "let the AI run arbitrary PowerShell" MCP tool. That felt like too much uncontrolled surface area for what was actually needed (running specific, known commands on one dev server), so this exists instead: deliberately minimal, deliberately hard to misuse.

Feedback welcome

This was built to solve a real problem, not as a polished product - if you try it, hit an issue, or have a better way to do something here, please open an issue. That's genuinely more useful than a star.

What this is NOT

It is not a general-purpose remote-execution tool. It exposes exactly one tool, run-ssh-command, which can only ever do one thing: send a command over SSH to a fixed user@host set by whoever deploys the server via environment variables. The AI model cannot choose or change the target - it isn't a parameter the model can pass in, it's fixed configuration. It cannot run local commands, and cannot touch the local filesystem directly.

Hardening built in

  • Fixed target, not a parameter. Host, user, and identity file come from environment variables set in your MCP client's config, not from anything the model can pass at call time.
  • Explicit confirmation gate. The tool requires confirmed: true to actually execute. Calling it without that (the default) just echoes back the command it would run, without running it. The intent is that your AI assistant is instructed to always show you the exact command and wait for your go-ahead before ever setting confirmed: true - this parameter is a technical backstop for that behaviour, not a replacement for it. (With Claude specifically: put this instruction directly in the tool's own description, as this project does, and additionally leave the tool's permission setting on "ask every time" rather than "always allow" in your client.)
  • No shell re-interpretation. Arguments are passed as an array via spawn(..., { shell: false }), not built as a concatenated string run through a shell.
  • Fails fast, never hangs silently. BatchMode=yes means if key auth doesn't work, the command errors out immediately instead of sitting there waiting for a password prompt nobody can answer. A timeout (default 30s, configurable) kills anything that hangs regardless.
  • Local audit log. Every command that actually executes is appended to logs/ssh-command-log.txt with a timestamp and exit code, independent of your AI client's own chat history.

What this does NOT protect against

Being direct about the actual limits, not overselling this:

  • confirmed: true is a contract the model is instructed to respect, not something this tool can verify was genuinely approved by a human. The real backstops are your AI client's own instructed behaviour and its per-tool permission prompt.
  • Once a command reaches the remote host, it runs as whatever user you configured - this tool doesn't add any privilege restriction on the remote side. If you want defence in depth, give the SSH user its own restricted, least-privilege account with scoped sudo, not your main account.
  • This is a small, unaudited piece of code - treat it with the same scepticism as any other tool that can execute commands on your behalf, not as a certified-secure product.

Setup

Prerequisites: Node.js 18+, and a working ssh client on your system.

  1. Clone or download this repo.
  2. npm install
  3. Generate (or reuse) an SSH keypair authorised on the target host, e.g.:
    ssh-keygen -t ed25519 -f ~/.ssh/hardened-ssh-mcp-key
    ssh-copy-id -i ~/.ssh/hardened-ssh-mcp-key.pub youruser@yourhost
    
  4. Copy claude_desktop_config.example.json and fill in your own values (host, user, key path), or add the equivalent env block to your existing MCP client config. See that file for the exact shape.
  5. Restart your MCP client.
  6. In your client's settings, leave this tool's permission on "ask every time," not "always allow."

Configuration reference

Variable Required Default Notes
SSH_USER yes - Remote username
SSH_HOST yes - Remote host (IP or hostname)
SSH_IDENTITY_FILE yes - Absolute path to your private key
SSH_KNOWN_HOSTS_FILE no your normal ~/.ssh/known_hosts See the Windows note below if this path contains spaces
SSH_EXECUTABLE no ssh (resolved via PATH) See the Windows note below
SSH_HOME no - Only needed in the Windows edge case below
SSH_CONNECT_TIMEOUT_SECONDS no 10
SSH_COMMAND_TIMEOUT_MS no 30000

Windows note: a real gotcha this project ran into

If you're running this on Windows with an MSIX-packaged AI client (this includes Claude Desktop's Microsoft Store-style installer path), you may hit a genuinely strange failure: Windows' native OpenSSH client (System32\OpenSSH\ssh.exe) exits with code 255 and completely empty output - no stdout, no stderr, not even for ssh -V with no network or keys involved. It works fine run manually, and even works fine from an identical standalone Node.js script - but fails silently the moment it's spawned as a child of the packaged client specifically.

Extensive diagnosis (Process Monitor tracing, elimination of every antivirus/firewall/sandboxing/process-isolation cause) pointed to ssh.exe's own startup code failing during a call into kernel.appcore.dll (a Windows DLL used to query an application's packaging/App Model identity) - plausibly because it inherits an incomplete package identity from an MSIX-packaged ancestor process, and doesn't handle that combination cleanly.

The practical fix: use Git for Windows' bundled SSH client instead of the native one. It's a completely different build (MSYS2/Cygwin-based, not Microsoft's MSVC-built port) and does not exhibit this failure under the identical condition. To use it:

  1. Install Git for Windows with the "Use bundled OpenSSH" option (not "Use external OpenSSH").
  2. Set SSH_EXECUTABLE to the bundled client's path, typically C:\Program Files\Git\usr\bin\ssh.exe.
  3. Set SSH_HOME to your user profile directory (e.g. C:\Users\yourname) - Git's MSYS2-based client needs HOME set explicitly to resolve correctly; Windows' native client does not need this.

If you'd rather keep using Windows' native OpenSSH and are hitting this, an alternative (more involved) workaround is to run this server as a standalone process reached via a stdio-to-HTTP bridge (e.g. mcp-remote) rather than letting your AI client spawn it directly - this avoids the failure entirely by ensuring ssh.exe is never a descendant of the packaged client process, at the cost of needing to start that process yourself before each session. Happy to point you at more detail on this if you land here from a search and it's relevant to your situation - open an issue.

Extending

A per-command allowlist/denylist, or a second, separately configured instance for an additional host, would both be straightforward additions to this pattern.

License

MIT - see LICENSE.

推荐服务器

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 模型以安全和受控的方式获取实时的网络信息。

官方
精选