{"id":49730974,"url":"https://github.com/oaslananka-lab/mcp-ssh-tool","last_synced_at":"2026-05-13T10:00:54.242Z","repository":{"id":356390170,"uuid":"1231952040","full_name":"oaslananka-lab/mcp-ssh-tool","owner":"oaslananka-lab","description":"Production-grade MCP SSH automation server for secure remote command, file, tunnel, service, metrics, and policy-controlled operations over stdio/HTTP, with npm distribution, MCP Registry metadata, and ChatGPT app readiness.","archived":false,"fork":false,"pushed_at":"2026-05-12T09:21:36.000Z","size":883,"stargazers_count":1,"open_issues_count":9,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T09:41:13.034Z","etag":null,"topics":["automation","chatgpt","claude","codex","cursor","devops","infrastructure","mcp","mcp-server","model-context-protocol","nodejs","npm-package","openai","remote-automation","security","sre","ssh","ssh-client","typescript","vscode"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/mcp-ssh-tool","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oaslananka-lab.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":["oaslananka"]}},"created_at":"2026-05-07T12:52:34.000Z","updated_at":"2026-05-12T09:21:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"56b58552-3c4f-47e6-89f6-1af67af29ca5","html_url":"https://github.com/oaslananka-lab/mcp-ssh-tool","commit_stats":null,"previous_names":["oaslananka-lab/mcp-ssh-tool"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/oaslananka-lab/mcp-ssh-tool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oaslananka-lab%2Fmcp-ssh-tool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oaslananka-lab%2Fmcp-ssh-tool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oaslananka-lab%2Fmcp-ssh-tool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oaslananka-lab%2Fmcp-ssh-tool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oaslananka-lab","download_url":"https://codeload.github.com/oaslananka-lab/mcp-ssh-tool/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oaslananka-lab%2Fmcp-ssh-tool/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32977273,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T06:31:55.726Z","status":"ssl_error","status_checked_at":"2026-05-13T06:31:51.336Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","chatgpt","claude","codex","cursor","devops","infrastructure","mcp","mcp-server","model-context-protocol","nodejs","npm-package","openai","remote-automation","security","sre","ssh","ssh-client","typescript","vscode"],"created_at":"2026-05-09T06:17:50.829Z","updated_at":"2026-05-13T10:00:54.205Z","avatar_url":"https://github.com/oaslananka-lab.png","language":"TypeScript","funding_links":["https://github.com/sponsors/oaslananka"],"categories":[],"sub_categories":[],"readme":"# mcp-ssh-tool\n\n[![npm version](https://img.shields.io/npm/v/mcp-ssh-tool.svg)](https://www.npmjs.com/package/mcp-ssh-tool)\n[![CI](https://github.com/oaslananka-lab/mcp-ssh-tool/actions/workflows/ci.yml/badge.svg)](https://github.com/oaslananka-lab/mcp-ssh-tool/actions/workflows/ci.yml)\n[![Security](https://github.com/oaslananka-lab/mcp-ssh-tool/actions/workflows/security.yml/badge.svg)](https://github.com/oaslananka-lab/mcp-ssh-tool/actions/workflows/security.yml)\n[![Official MCP Registry](https://img.shields.io/badge/MCP%20Registry-active-green.svg)](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.oaslananka%2Fmcp-ssh-tool/versions/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![npm downloads](https://img.shields.io/npm/dm/mcp-ssh-tool.svg)](https://www.npmjs.com/package/mcp-ssh-tool)\n\nProduction-grade MCP SSH automation for operators, developers, and AI clients. `mcp-ssh-tool` opens persistent SSH sessions and exposes safe, structured tools for command execution, file operations, transfers, tunnels, package/service management, metrics, resources, and guided prompts.\n\nv2 is secure by default: strict host-key verification is on, root login is off, raw sudo is policy-gated, destructive commands and filesystem mutations are denied unless policy allows them, and remote HTTP starts on loopback only unless bearer auth and allowed origins are configured.\n\n## Why This Server\n\n- **Trust:** central policy engine, structured audit events, redacted logs, strict host keys, and machine-readable errors.\n- **MCP quality:** stdio for local clients, Streamable HTTP for remote clients, legacy SSE only behind an explicit compatibility flag.\n- **AI-friendly tools:** stable output schemas, `structuredContent`, annotations for read-only/destructive/idempotent behavior, resources, and curated prompts.\n- **Operations:** session TTL/eviction, command timeouts, transfer checksum verification, real SSH forwarding, Prometheus metrics, and OpenTelemetry hooks.\n- **Portability:** SFTP first, POSIX/BusyBox-aware shell fallbacks for basic file operations, and explicit support boundaries.\n\n## Quick Start\n\nRun without installing:\n\n```bash\npnpm dlx mcp-ssh-tool --version\n```\n\nOr install globally:\n\n```bash\npnpm add --global mcp-ssh-tool\n```\n\nAdd a stdio MCP server to your client:\n\n```json\n{\n  \"servers\": {\n    \"ssh-mcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"mcp-ssh-tool\",\n      \"args\": []\n    }\n  }\n}\n```\n\nUse it from your MCP client:\n\n```text\nOpen a safe SSH session to prod-1 as deploy, inspect host capabilities, then show disk usage.\n```\n\n## Requirements\n\n- Node.js `22.22.2+` or `24.14.1+` (LTS only)\n- SSH access to target hosts\n- A populated `known_hosts` file for strict host verification, or an explicit per-session host-key policy\n\n## Transports\n\n| Mode | Command | Use When |\n|------|---------|----------|\n| stdio | `mcp-ssh-tool` | Local desktop clients such as ChatGPT, Claude Desktop, VS Code, Cursor, or Codex. |\n| Streamable HTTP | `mcp-ssh-tool --transport=http --host 127.0.0.1 --port 3000` | Remote MCP clients, reverse proxies, or Inspector sessions. |\n| legacy SSE | `mcp-ssh-tool --transport=http --enable-legacy-sse` | Temporary v1 compatibility only. Prefer Streamable HTTP. |\n\nNon-loopback HTTP startup is refused unless both `--bearer-token-file` and allowed origins are configured.\n\n## Secure Defaults\n\n| Area | v2 Default |\n|------|------------|\n| Host keys | `hostKeyPolicy=strict`, `knownHostsPath=~/.ssh/known_hosts` |\n| Root SSH login | denied |\n| Raw `proc_sudo` | denied unless `allowRawSudo=true` |\n| Destructive commands | denied unless `allowDestructiveCommands=true` |\n| Destructive fs operations | allowed only under policy prefixes, denied elsewhere |\n| Local transfer paths | `file_upload` and `file_download` limited to OS temp unless policy allows more |\n| HTTP bind | `127.0.0.1` |\n| Legacy SSE | disabled |\n| File reads | size-limited by `SSH_MCP_MAX_FILE_SIZE` |\n| Command output | bounded by `SSH_MCP_MAX_COMMAND_OUTPUT_BYTES` |\n| Transfers | bounded by `SSH_MCP_MAX_TRANSFER_BYTES` |\n\nPer-session `policyMode: \"explain\"` returns a plan/verdict without executing. Use it before mutations when an AI client needs to summarize risk.\n\n## Policy Example\n\nSet `SSH_MCP_POLICY_FILE=/etc/mcp-ssh-tool/policy.json`:\n\n```json\n{\n  \"mode\": \"enforce\",\n  \"allowRootLogin\": false,\n  \"allowRawSudo\": false,\n  \"allowDestructiveCommands\": false,\n  \"allowDestructiveFs\": false,\n  \"allowedHosts\": [\"^prod-[0-9]+\\\\.example\\\\.com$\"],\n  \"commandAllow\": [\"^(uname|df|uptime|systemctl status)\\\\b\"],\n  \"commandDeny\": [\"rm\\\\s+-rf\\\\s+/\", \"shutdown\", \"reboot\"],\n  \"pathAllowPrefixes\": [\"/tmp\", \"/var/tmp\", \"/home/deploy\"],\n  \"pathDenyPrefixes\": [\"/etc/shadow\", \"/etc/sudoers\", \"/boot\", \"/dev\", \"/proc\"],\n  \"localPathAllowPrefixes\": [\"/var/tmp/mcp-ssh-tool\"],\n  \"localPathDenyPrefixes\": []\n}\n```\n\nSimple deploys can use environment overrides such as `SSH_MCP_ALLOW_RAW_SUDO=true`, `SSH_MCP_ALLOWED_HOSTS=prod-1.example.com`, `SSH_MCP_PATH_ALLOW_PREFIXES=/tmp,/home/deploy`, or `SSH_MCP_LOCAL_PATH_ALLOW_PREFIXES=/var/tmp/mcp-ssh-tool`.\n\n## Core Tools\n\n- `ssh_open_session`, `ssh_close_session`, `ssh_list_sessions`, `ssh_ping`, `ssh_list_configured_hosts`, `ssh_resolve_host`\n- `proc_exec`, `proc_sudo`, `proc_exec_stream`\n- `fs_read`, `fs_write`, `fs_list`, `fs_stat`, `fs_mkdirp`, `fs_rmrf`, `fs_rename`\n- `file_upload`, `file_download`\n- `ensure_package`, `ensure_service`, `ensure_lines_in_file`, `patch_apply`\n- `os_detect`, `get_metrics`\n- `tunnel_local_forward`, `tunnel_remote_forward`, `tunnel_list`, `tunnel_close`\n\nAll tools return text plus stable `structuredContent`. Tool metadata includes titles, output schemas, and annotations that disclose read-only, destructive, idempotent, and external side-effect behavior.\n\n## Resources And Prompts\n\nResources:\n\n- `mcp-ssh-tool://sessions/active`\n- `mcp-ssh-tool://metrics/json`\n- `mcp-ssh-tool://metrics/prometheus`\n- `mcp-ssh-tool://ssh-config/hosts`\n- `mcp-ssh-tool://policy/effective`\n- `mcp-ssh-tool://audit/recent`\n- `mcp-ssh-tool://capabilities/support-matrix`\n\nPrompts:\n\n- `safe-connect`\n- `inspect-host-capabilities`\n- `plan-mutation`\n- `managed-config-change`\n\n## Support Matrix\n\n| Target | Status |\n|--------|--------|\n| Linux | Full support. |\n| macOS/BSD | Session, process, fs, and transfer supported; package/service helpers only where tested. |\n| BusyBox/dropbear | Experimental for session, process, and basic fs fallbacks. |\n| Windows SSH targets | Experimental for session, process, fs, and transfer; no `proc_sudo` or `ensure_*`. |\n\n## Client Examples\n\nChatGPT or Claude Desktop:\n\n```json\n{\n  \"mcpServers\": {\n    \"ssh-mcp\": {\n      \"command\": \"pnpm\",\n      \"args\": [\"dlx\", \"mcp-ssh-tool\"]\n    }\n  }\n}\n```\n\nVS Code or Cursor:\n\n```json\n{\n  \"servers\": {\n    \"ssh-mcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"mcp-ssh-tool\"\n    }\n  }\n}\n```\n\nMCP Inspector over HTTP:\n\n```bash\nprintf '%s' 'super-secret-token' \u003e .mcp-token\nmcp-ssh-tool --transport=http --host 127.0.0.1 --port 3000 --bearer-token-file .mcp-token\n```\n\n## Configuration\n\nHigh-value environment variables:\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `SSH_MCP_POLICY_FILE` | unset | Canonical JSON policy source. |\n| `SSH_MCP_HOST_KEY_POLICY` | `strict` | `strict`, `accept-new`, or `insecure`. |\n| `SSH_MCP_KNOWN_HOSTS_PATH` | `~/.ssh/known_hosts` | Known-hosts file for strict verification. |\n| `SSH_MCP_MAX_FILE_SIZE` | `10485760` | Max bytes for `fs_read`. |\n| `SSH_MCP_MAX_COMMAND_OUTPUT_BYTES` | `1048576` | Max retained stdout/stderr bytes per command or stream. |\n| `SSH_MCP_MAX_STREAM_CHUNKS` | `4096` | Max retained streaming chunks before truncation metadata is returned. |\n| `SSH_MCP_MAX_TRANSFER_BYTES` | `52428800` | Max bytes for `file_upload` and `file_download`. |\n| `SSH_MCP_COMMAND_TIMEOUT` | `30000` | Default command timeout. |\n| `SSH_MCP_HTTP_HOST` | `127.0.0.1` | Streamable HTTP bind host. |\n| `SSH_MCP_HTTP_PORT` / `PORT` | `3000` | Streamable HTTP port. |\n| `SSH_MCP_HTTP_MAX_REQUEST_BODY_BYTES` | `1048576` | Max JSON request bytes accepted by Streamable HTTP. |\n| `SSH_MCP_LOCAL_PATH_ALLOW_PREFIXES` | OS temp directory | Local transfer allow-list for `file_upload` and `file_download`. |\n| `SSH_MCP_HTTP_BEARER_TOKEN_FILE` | unset | Required for non-loopback HTTP. |\n| `SSH_MCP_HTTP_ALLOWED_ORIGINS` | loopback origins | Comma-separated allowed origins. |\n\nDeprecated aliases `STRICT_HOST_KEY_CHECKING` and `SSH_MCP_STRICT_HOST_KEY` are still accepted for one v2 compatibility cycle. Prefer `SSH_MCP_HOST_KEY_POLICY`.\n\n## Development\n\nUse the exact local runtime from `.nvmrc` / `.node-version`, then run:\n\n```bash\npnpm install --frozen-lockfile\npnpm run check\n```\n\nLive SSH suites are opt-in:\n\n```bash\nRUN_SSH_INTEGRATION=1 pnpm run test:integration\nRUN_SSH_E2E=1 pnpm run test:e2e\n```\n\nLocal quality gates are layered:\n\n- `pre-commit`: formats staged files and lints staged TypeScript only\n- `pre-push`: runs `pnpm run check:push`\n- `task hooks`: runs tracked pnpm hooks plus `.pre-commit-config.yaml` hooks when `pre-commit` is installed\n- manual/full parity: `task ci` or `pnpm run check`\n\n## CI/CD Ownership\n\nThe personal repository `https://github.com/oaslananka/mcp-ssh-tool` is the source repository. The organization repository `https://github.com/oaslananka-lab/mcp-ssh-tool` is the GitHub Actions, CI/CD, release, security, and provenance boundary.\n\nAutomatic CI/CD, supply-chain security checks, trusted npm publishing, MCP Registry publishing, GitHub Releases, Docker image validation, SBOMs, attestations, and release decisions run only from the org repository. Personal-repo Actions are intentionally not required gates.\n\nThe two repositories must stay content-identical for `main`, release tags, releases, labels, milestones, and active collaboration state. Org release-generated refs are backfilled to the personal source repository.\n\nThe npm package `repository.url` intentionally points at the org automation repository so npm provenance can verify that the published artifact came from the same GitHub Actions repository that built it. The MCP Registry server name remains `io.github.oaslananka/mcp-ssh-tool` because it is already published and changing it would break existing users.\n\nSee [docs/ci-cd-topology.md](docs/ci-cd-topology.md) for mirror, release, dry-run, and manual fallback guidance.\n\n## Documentation\n\n- [ARCHITECTURE.md](ARCHITECTURE.md)\n- [SECURITY_DECISIONS.md](SECURITY_DECISIONS.md)\n- [MIGRATION.md](MIGRATION.md)\n- [docs/ci-cd-topology.md](docs/ci-cd-topology.md)\n- [docs/development.md](docs/development.md)\n- [docs/release.md](docs/release.md)\n- [docs/publishing.md](docs/publishing.md)\n- [docs/npm-provenance.md](docs/npm-provenance.md)\n- [docs/mcp-registry.md](docs/mcp-registry.md)\n- [docs/chatgpt-app.md](docs/chatgpt-app.md)\n- [docs/doppler.md](docs/doppler.md)\n- [docs/operations.md](docs/operations.md)\n- [docs/repository-operations.md](docs/repository-operations.md)\n- [docs/docker.md](docs/docker.md)\n- [docs/client-configs.md](docs/client-configs.md)\n- [docs/security/release-integrity.md](docs/security/release-integrity.md)\n- [docs/security/chatgpt-app-threat-model.md](docs/security/chatgpt-app-threat-model.md)\n- [docs/security/ssh-threat-model.md](docs/security/ssh-threat-model.md)\n- [docs/branch-protection.md](docs/branch-protection.md)\n- [docs/maintenance-policy.md](docs/maintenance-policy.md)\n- [docs/api-stability.md](docs/api-stability.md)\n- [docs/threat-model.md](docs/threat-model.md)\n- [docs/configuration.md](docs/configuration.md)\n- [docs/security-model.md](docs/security-model.md)\n- [docs/troubleshooting.md](docs/troubleshooting.md)\n- [docs/enterprise-deployment.md](docs/enterprise-deployment.md)\n\n## License\n\nMIT License. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foaslananka-lab%2Fmcp-ssh-tool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foaslananka-lab%2Fmcp-ssh-tool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foaslananka-lab%2Fmcp-ssh-tool/lists"}