AI 에이전트가 감사 로그 및 명령 정책을 기반으로 제어된 SSH 명령과 SFTP 파일 전송을 수행할 수 있도록 중앙 집중식 HTTP 게이트웨이를 제공합니다.
다른 이름 gelse/ssh-mcp
- 스타
- 8
- Tools
- 6
- 다운로드, 30일
- —
- 최신 버전
- 0.3.0
- 마지막 커밋
- 2026년 9월 16일
- 라이선스
- MIT
ssh MCP란?
ssh은(는) MCP server입니다. AI 에이전트가 감사 로그 및 명령 정책을 기반으로 제어된 SSH 명령과 SFTP 파일 전송을 수행할 수 있도록 중앙 집중식 HTTP 게이트웨이를 제공합니다. 6개 도구를 제공합니다. 예: ssh_list_servers, ssh_list_allowed_commands, ssh_execute_command.
프로젝트 README에서 생성된 요약
ssh MCP server 정보
중앙 집중식 HTTP 게이트웨이를 통해 제어된 SSH 및 SFTP 기능을 제공함으로써 여러 AI 에이전트의 원격 서버 액세스 관리를 더욱 안전하게 만듭니다. 클라이언트마다 개별 로컬 프로세스를 실행하는 대신, 이 서버는 엄격한 명령 정책과 감사 로그를 적용하면서 SSH 대상에 연결하는 단일 진입점 역할을 합니다. SSH 키가 무분별하게 생성되는 것을 방지하고 에이전트가 인프라에서 실행하는 명령을 가시적으로 관리해야 하는 운영 팀을 위해 설계되었습니다.
사용자는 Docker를 통해 서버를 배포하고 API key로 인증하여 streamable HTTP를 통해 MCP 클라이언트를 연결합니다. 시스템은 ssh_list_servers, ssh_list_allowed_commands, ssh_execute_command, ssh_check_connection, ssh_download_file, ssh_upload_file의 6가지 특정 도구를 제공합니다. 이 서버는 9단계 권한 부여 체인, 세션 재사용을 위한 커넥션 풀링, 그리고 폭주하는 에이전트가 호스트에 과부하를 주는 것을 방지하는 속도 제한(rate limiting)을 통해 차별화됩니다. 설정은 JSON 파일을 통해 관리되며, 대상 및 명령 허용 목록에 대한 핫 리로드를 지원합니다.
활용 사례
- 1원격 에이전트 활동 감사개발자는 구조화된 JSONL 로그를 통해 AI 에이전트가 수행한 모든 명령과 권한 부여 결정을 추적할 수 있습니다.
- 2에이전트 권한 제한관리자는 대상별로 허용된 특정 명령을 정의하여 에이전트가 안전한 작업만 수행하도록 보장할 수 있습니다.
- 3SFTP를 통한 단일 파일 전송AI 클라이언트는 보안 파일 전송 도구를 사용하여 원격 서버로 또는 원격 서버로부터 개별 파일을 이동할 수 있습니다.
- 4서버 과부하 방지게이트웨이는 속도 제한을 사용하여 단일 에이전트가 분당 설정된 요청 수를 초과하지 않도록 합니다.
프로젝트의 README를 바탕으로 작성되었습니다. 모든 활용 사례는 해당 내용의 인용문과 대조하여 확인합니다.
ssh MCP 설치 방법
형식 확인: 2026년 11월 10일Cursor에 추가Goose에 추가Claude Code에 ssh MCP 설치
$ claude mcp add --env 'CONFIG_API_TOKEN=<YOUR_CONFIG_API_TOKEN>' ssh-mcp -- docker run -i --rm ghcr.io/gelse/ssh-mcp:0.3.0Cursor에 ssh MCP 설치
~/.cursor/mcp.json
{
"mcpServers": {
"ssh-mcp": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/gelse/ssh-mcp:0.3.0"
],
"env": {
"CONFIG_API_TOKEN": "<YOUR_CONFIG_API_TOKEN>"
}
}
}
}VS Code에 ssh MCP 설치
.vscode/mcp.json
{
"servers": {
"ssh-mcp": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/gelse/ssh-mcp:0.3.0"
],
"env": {
"CONFIG_API_TOKEN": "<YOUR_CONFIG_API_TOKEN>"
}
}
}
}VS Code CLI에 ssh MCP 설치
$ code --add-mcp '{"name":"ssh-mcp","type":"stdio","command":"docker","args":["run","-i","--rm","ghcr.io/gelse/ssh-mcp:0.3.0"],"env":{"CONFIG_API_TOKEN":"<YOUR_CONFIG_API_TOKEN>"}}'Claude Desktop에 ssh MCP 설치
claude_desktop_config.json
{
"mcpServers": {
"ssh-mcp": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/gelse/ssh-mcp:0.3.0"
],
"env": {
"CONFIG_API_TOKEN": "<YOUR_CONFIG_API_TOKEN>"
}
}
}
}Codex에 ssh MCP 설치
$ codex mcp add ssh-mcp --env 'CONFIG_API_TOKEN=<YOUR_CONFIG_API_TOKEN>' -- docker run -i --rm ghcr.io/gelse/ssh-mcp:0.3.0Codex config.toml에 ssh MCP 설치
~/.codex/config.toml
[mcp_servers.ssh-mcp] command = "docker" args = ["run", "-i", "--rm", "ghcr.io/gelse/ssh-mcp:0.3.0"] [mcp_servers.ssh-mcp.env] CONFIG_API_TOKEN = "<YOUR_CONFIG_API_TOKEN>"
Gemini CLI에 ssh MCP 설치
$ gemini mcp add -s user -e 'CONFIG_API_TOKEN=<YOUR_CONFIG_API_TOKEN>' ssh-mcp docker -- run -i --rm ghcr.io/gelse/ssh-mcp:0.3.0Gemini settings.json에 ssh MCP 설치
~/.gemini/settings.json
{
"mcpServers": {
"ssh-mcp": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/gelse/ssh-mcp:0.3.0"
],
"env": {
"CONFIG_API_TOKEN": "<YOUR_CONFIG_API_TOKEN>"
}
}
}
}ssh MCP 도구 6
README에서 감지됨ssh_list_serversssh_list_allowed_commandsssh_execute_commandssh_check_connectionssh_download_filessh_upload_file
| ssh_list_servers | — | |
| ssh_list_allowed_commands | — | |
| ssh_execute_command | — | |
| ssh_check_connection | — | |
| ssh_download_file | — | |
| ssh_upload_file | — |
구성
CONFIG_API_TOKEN비밀Bearer token for the configuration API
CONFIG_API_ENABLEDEnable the configuration REST API and web dashboard
CONFIG_DIRDirectory containing ssh-mcp-config.json
LOG_DIRDirectory for JSONL audit logs
| 이름 | 설명 | 유형 |
|---|---|---|
| CONFIG_API_TOKEN | Bearer token for the configuration API | 비밀 |
| CONFIG_API_ENABLED | Enable the configuration REST API and web dashboard | |
| CONFIG_DIR | Directory containing ssh-mcp-config.json | |
| LOG_DIR | Directory for JSONL audit logs |
자동 검사
2026년 11월 12일에 실행됨전체 보고서 →자동 검사를 통과했습니다. 이는 보안 감사가 아닙니다. 코드를 직접 읽고 서버에 필요한 최소한의 권한만 부여하십시오. 검사 방식
- 소스 저장소 연결 및 접근 가능통과
- 오픈 소스 라이선스 (OSI)통과
- 최근 1년 내 커밋 또는 릴리스통과
- 패키지 이름이 인기 패키지와 유사하지 않음검사되지 않음
- 원격 엔드포인트가 HTTPS 사용검사되지 않음
- 파괴적인 도구에 라벨 표시됨통과
- 모델에 대한 숨겨진 지침 없음통과
- 패키지 및 해당 종속성에 중요한 보안 권고 없음검사되지 않음
README
GitHub에서 보기ssh-mcp
A centralized MCP gateway that gives AI agents controlled SSH access over Streamable HTTP.
What problem does this solve?
Most MCP SSH servers run as local stdio processes — one per client, with no shared state, no centralized authorization, and no audit trail. When multiple AI agents need SSH access, each manages its own SSH keys and runs its own process. This creates:
- No centralized access control — every client decides what it can run
- No audit trail — commands are invisible to the ops team
- SSH key sprawl — keys scattered across every agent machine
- No rate limiting — a runaway agent can overwhelm a target
ssh-mcp solves this by deploying a single HTTP gateway. All clients connect to it; it connects to your SSH targets. Authorization, rate limiting, connection pooling, and audit logging happen in one place.
Quick Start
Using the pre-built image (recommended)
docker compose pull
docker compose up -d
The image is published at ghcr.io/gelse/ssh-mcp:latest.
The compose file maps host port 9080 to container port 8080.
Verify the server is running:
curl http://localhost:9080/health
# → {"status": "ok"}
Create a minimal config in config/ssh-mcp-config.json:
{
"version": 1,
"ssh_targets": {
"my-server": {
"host": "10.0.1.10",
"username": "deploy"
}
},
"allowed_commands": {
"default": [
{
"targets": ["*"],
"commands": ["hostname", "uptime", "free", "df"]
}
]
}
}
Generate an API key hash and add it to your config or
secrets.json (see Configuration).
make build
docker compose up -d --build
What you can do (tools)
Six MCP tools are available over Streamable HTTP:
| Tool | Description |
|---|---|
ssh_list_servers |
List configured SSH targets |
ssh_list_allowed_commands |
Show allowed commands for a target |
ssh_execute_command |
Execute a command on a remote server |
ssh_check_connection |
Test SSH connectivity to a target |
ssh_download_file |
Download a file via SFTP |
ssh_upload_file |
Upload a file via SFTP |
Tool Naming Convention
All tools follow the pattern ssh_<verb>_<noun>:
ssh_list_servers— list resourcesssh_list_allowed_commands— list permissionsssh_execute_command— perform an actionssh_check_connection— verify connectivityssh_download_file/ssh_upload_file— file transfer
See examples/README.md for usage examples
including curl commands and Python client code.
What's configurable
ssh-mcp is configured via JSON files with hot-reload (15 s poll, 2 s debounce). Key areas:
| Area | Details |
|---|---|
| SSH targets | Host, port, username, key, password |
| Command policies | Block patterns, per-key/network allowlists |
| Connection pool | Max connections, idle timeout, concurrency |
| Rate limiting | Per-IP sliding window (default 60 req/min) |
| Logging | JSONL with rotation, gzip, multiple targets |
| SFTP | Sandbox root, path length limits |
Full reference: docs/CONFIGURATION.md
| File | Purpose |
|---|---|
ssh-mcp-config.json |
Main config |
config.schema.json |
JSON Schema for validation |
secrets.json |
Passwords and API key hashes |
MCP_SSH_* env vars |
Overrides for any setting |
Why not just raw SSH / other MCP servers?
ssh-mcp adds a layered authorization chain (9 ordered layers) between every client request and every SSH command. Per-API-key and per-network rules let different agents get different permissions on different servers — without touching the underlying SSH accounts.
Additional protections:
- Circuit breakers isolate failing targets with exponential backoff
- Rate limiting prevents runaway agents from overwhelming hosts
- Structured audit logs trace every command, client, IP, and authorization decision
- Connection pooling reuses SSH sessions across requests
- Input sanitization and dangerous-pattern detection block shell injection attempts
Architecture: ARCHITECTURE.md
Security model: docs/SECURITY.md
What it is NOT
- Not an interactive shell — commands are executed individually with structured output
- Not a file manager — SFTP supports single-file download and upload only (no directory listing or recursive transfer)
- Not a firewall / network ACL — authorization is command-level, not network-level
- Does not reduce SSH account privileges — if a command is allowed, the SSH user executes it with whatever privileges that account has
Not yet / known gaps
Fixable with contribution:
- SFTP is single-file only — no directory listing or recursive transfer
- No TLS termination — run Traefik or nginx in front
- No OAuth or mTLS app-layer authentication
- Rate limiter settings are not hot-reloadable (set at boot)
Architectural:
- Config API dashboard login sessions are in-memory only — they don't survive restarts and the API is single-instance (config changes themselves persist to the config file normally)
- No tamper protection for audit logs
Observability
- Health:
GET /health— returns{"status": "ok"} - Metrics:
GET /metrics— Prometheus exposition format - Logging: Structured JSONL with request correlation
Full reference: docs/OBSERVABILITY.md
Config API & Dashboard
An optional web dashboard for managing configuration without
editing JSON files. Enable with CONFIG_API_ENABLED=true.
Full reference: docs/CONFIG-API.md
FAQ
Dashboard returns 401 over HTTP
The session cookie defaults to Secure (HTTPS only). For local
HTTP testing, set:
environment:
- CONFIG_API_SESSION_COOKIE_SECURE=false
Then restart the container.
How do MCP clients connect?
Connect to http://host:9080/mcp using the Streamable HTTP
transport. Pass your API key via X-API-Key or
Authorization: Bearer header.
How do I generate an API key hash?
docker compose exec mcp-ssh python -c \
"from lib.crypto import hash_api_key; print(hash_api_key('your-key'))"
# → pbkdf2:sha256:100000$<salt>$<hash>
Or use the hash utility in the Config API dashboard.
How does hot reload work?
The config file is polled every 15 seconds with a 2-second debounce. Changes to targets, commands, and settings take effect without restart. Rate limiter and log target settings require a restart.
Why was my command denied?
Commands are evaluated through a 9-layer authorization chain.
The matched_via field in logs shows which layer denied.
See Security Model for the full chain.
How does rate limiting work?
Per-IP sliding window, default 60 requests per 60 seconds.
Exceeding the limit returns HTTP 503. Configure via
settings.rate_limit in the config file.
Where do logs go?
Logs are written to the /logs volume (mapped from ./logs).
The active log file is ssh-mcp.log in JSONL format with
optional gzip rotation.
Troubleshooting basics
# Check server health
curl http://localhost:9080/health
# Validate config
make config-test
# Check logs
docker compose logs mcp-ssh
Documentation
| Document | Description |
|---|---|
ARCHITECTURE.md |
System design and data flow |
docs/SECURITY.md |
Security model and threat analysis |
docs/CONFIGURATION.md |
Full config reference |
docs/CONFIG-API.md |
Config API & dashboard |
docs/OBSERVABILITY.md |
Health, metrics, logging |
CONTRIBUTING.md |
Development and contribution guide |
CHANGELOG.md |
Release history |
examples/ |
Config examples and client code |
Development
# Unit tests
make test
# Integration tests (builds Docker image)
make integrationtest
See CONTRIBUTING.md for the full development
guide, coding conventions, and PR workflow.
Roadmap
No public roadmap. See Not yet / known gaps for current limitations and opportunities.
License
ssh MCP 질문
ssh MCP를 Claude Code에 추가하려면 어떻게 하나요?
터미널에서 claude mcp add --env 'CONFIG_API_TOKEN=<YOUR_CONFIG_API_TOKEN>' ssh-mcp -- docker run -i --rm ghcr.io/gelse/ssh-mcp:0.3.0를 실행합니다. 모든 프로젝트에서 사용할 수 있게 하려면 --scope user를 추가합니다.
ssh MCP를 Cursor에 추가하려면 어떻게 하나요?
~/.cursor/mcp.json를 열고 mcpServers 아래에 서버를 추가합니다. 위 설치 섹션에 표시된 Cursor 구성을 사용합니다.
ssh MCP는 어떤 도구를 제공하나요?
6개 도구를 제공합니다. 예: ssh_list_servers, ssh_list_allowed_commands, ssh_execute_command, ssh_check_connection, ssh_download_file.
MCP 클라이언트는 어떻게 연결하나요?
클라이언트는 지정된 호스트 및 포트에서 streamable HTTP 전송 방식을 사용하여 연결하며, 헤더에 API key를 전달합니다.
대화형 셸을 지원하나요?
아니요, 이 서버는 대화형 셸이 아닙니다. 명령은 구조화된 출력과 함께 개별적으로 실행됩니다.
핫 리로드(hot reload)는 어떻게 작동하나요?
설정 파일을 15초마다 폴링하며 2초의 디바운스(debounce)를 적용합니다. 이를 통해 서버 재시작 없이 변경 사항을 적용할 수 있습니다.